java tcp客户端:如何边读边发送数据

java tcp client: howto send data while reading

这是我使用套接字连接的第一步 java。我喜欢编写连接到服务器并读取服务器将发送的所有数据的 tcp 客户端。来自服务器的每条消息将由 0x00 终止。

第一个问题: 我如何读取这个可变消息长度?

第二个问题: 如果用户通过键盘输入文本,则该文本应在我接收时发送到服务器。但是如何在从服务器读取数据的同时发送数据呢?

到目前为止,这是我的代码:

import java.io.*;

 public class Client {
     public static void main(String[] args) {
    Client client = new Client();
    try {
        client.test();
    } catch (IOException e) {
        e.printStackTrace();
    }
     }
     void test() throws IOException {
    String ip = "127.0.0.1"; // localhost
    int port = 12345;
    java.net.Socket socket = new java.net.Socket(ip,port); // verbindet sich mit Server
    String zuSendendeNachricht = "Hello World0x00";
    schreibeNachricht(socket, zuSendendeNachricht);
    while (true){
        String empfangeneNachricht = leseNachricht(socket);
        System.out.println(empfangeneNachricht);
        }
     }
     void schreibeNachricht(java.net.Socket socket, String nachricht) throws IOException {
     PrintWriter printWriter =
        new PrintWriter(
        new OutputStreamWriter(
            socket.getOutputStream()));
    printWriter.print(nachricht);
    printWriter.flush();
    }
    String leseNachricht(java.net.Socket socket) throws IOException {
    BufferedReader bufferedReader =
        new BufferedReader(
        new InputStreamReader(
            socket.getInputStream()));
    char[] buffer = new char[200];
        int anzahlZeichen = bufferedReader.read(buffer, 0, 200); // blockiert bis Nachricht empfangen
        String nachricht = new String(buffer, 0, anzahlZeichen);
        System.out.println(nachricht);
    }
 }

以及如何读取可变消息长度

第一个问题:如何读取这个可变消息长度?

只需读取大小为 1 字节的传入数据并检查 0x00 上的每个字节。

第二个问题:如果用户通过键盘输入文本,这个文本应该发送到服务器,而我正在接收。但是如何在从服务器读取数据的同时发送数据呢?

启动两个独立的线程。一种用于阅读,一种用于写作。 伪代码:

Thread readingThread = new Thread(new Runnable() {
  @Override
  public void run() {
    //do reading here...
  }
});
readingThread.start();

Thread writingThread = new Thread(new Runnable() {
  @Override
  public void run() {
    //do writing here...
  }
});
writingThread.start();

在下面找到一个读取每个字节并检查 0x00 的工作示例。这里没有使用线程。

Client.java的内容:

package tcpserverclient;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Client {

    private static final Logger LOG = Logger.getLogger(Client.class.getName());

    private String getData(InputStream stream2server) {
        BufferedInputStream inputStream = new BufferedInputStream(stream2server);

        StringBuilder incomingData = new StringBuilder("");
        try {
            int c;
            LOG.info("reading incoming data...");
            while ((c = inputStream.read()) != -1) {
                if (c == 0) {
                    break;
                } else {
                    incomingData.append((char) c);
                    System.out.print((char) c);
                }
            }
            LOG.info("\ndata complete.");
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        return incomingData.toString();
    }

    private void startListen(int port) {
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            while (true) {
                LOG.info("\nListening on port " + port);
                Socket socket = serverSocket.accept();
                LOG.info("incoming call...");

                InputStream incoming = socket.getInputStream();
                OutputStream outgoing = socket.getOutputStream();
                String data = getData(incoming);
                LOG.info(data);

                outgoing.close();
                incoming.close();
                socket.close();
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Client().startListen(9999);
    }
}

Server.java的内容:

package tcpserverclient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class Server {

    public void sendCommand(String ip, int port, String cmd) {
        try {
            Socket socket = new Socket(ip, port);
            InputStream fromServer = socket.getInputStream();
            OutputStream toServer = socket.getOutputStream();
            socket.setSoTimeout(0);

            byte[] ba = cmd.getBytes();
            byte[] ba0 = new byte[ba.length + 1];
            System.arraycopy(ba, 0, ba0, 0, ba.length);
            ba0[ba.length] = 0;

            toServer.write(ba0);

            fromServer.close();
            toServer.close();
            socket.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new Server().sendCommand("127.0.0.1", 9999, "Hal, can you read me?");
    }
}

先启动 Client.java,然后启动 Server.java。输出是这样的:

run:
Jan 06, 2015 9:19:42 AM tcpserverclient.Client startListen
Information: 
Listening on port 9999
Jan 06, 2015 9:19:44 AM tcpserverclient.Client startListen
Information: incoming call...
Jan 06, 2015 9:19:44 AM tcpserverclient.Client getData
Information: reading incoming data...
Jan 06, 2015 9:19:44 AM tcpserverclient.Client getData
Information: 
data complete.
Jan 06, 2015 9:19:44 AM tcpserverclient.Client startListen
Information: Hal, can you read me?
Jan 06, 2015 9:19:44 AM tcpserverclient.Client startListen
Information: 
Listening on port 9999
Hal, can you read me?

您能否修改服务器以使用行结尾而不是“0x00”来终止消息?如果是这样,那么您将能够使用 readLine 而不是使用 bufferedReader 进行读取,这将允许您读取可变消息。

您不需要在每次循环运行时都初始化 bufferedReader,您可以在开始时初始化它,然后在循环中调用 read/write 方法。

要边读边写,您需要有一个从 stdin 读取的 BufferedReader,然后您需要在我之前提到的 while 循环中从它读取并写入您的输出流。

此页面包含所有代码示例和解释:http://docs.oracle.com/javase/tutorial/networking/sockets/readingWriting.html