Socket通信是Java网络编程中比较基础的部分,其原理其实就是源ip,源端口和目的ip,目的端口组成的套接字通信。其底层还设及到了TCP协议的通信。

Java中的Socket通信可以通过客户端的Socket与服务端的ServerSocket通信,同时利用IO流传递数据,也就是说Socket通信是面向流的使用的是BIO,并不同于后来的NIO通信面向缓冲。Socket通信中使用的IO流的read,readline等函数都是阻塞的,这就导致了在通信过程中,双方不能确定什么时侯是流的结束,针对这种可以通过约定结束符的方式进行结束,也可以约定一次传输的字节流的长度。下面通过代码进行说明

客户端

建立客户端线程,在run方法中不断对服务端进行发送消息,模拟多个客户端的通信,通过写入换行符,表明这次通信的结束。

 1 class Client implements Runnable {
 2
 3     private byte[] targetIp;
 4     private int port;
 5
 6     Client(byte[] ip, int port) {
 7         this.targetIp = ip;
 8         this.port = port;
 9     }
10
11     @Override
12     public void run() {
13         try {
14             InetAddress inetAddress = InetAddress.getByAddress(targetIp);
15             Socket socket = new Socket(inetAddress, port);
16             System.out.println("client");
17             BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
18             BufferedWriter socketOutput = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
19
20             int i = 0;
21             String NAME = "Client";
22             while (true) {
23                 socketOutput.write("This msg from " + NAME + " msg id is " + i);
24                 socketOutput.write("\n");//约定结束符表示流的结束
25                 i++;
26                 socketOutput.flush();
27                 System.out.println("here");
28                 String str = null;
29                 if (!(str = socketInput.readLine()).equals("\n")) {
30                     System.out.println(str);
31                 }
32
33             }
34
35             /*socket.shutdownInput();
36             socket.shutdownOutput();*/
37         } catch (IOException e) {
38             e.printStackTrace();
39         }
40
41     }
42 }

服务端

服务端通过accept接受客户端的连接,这个操作是阻塞的,直到有客户端的连接才能进行下一步。

 1 class Server implements Runnable {
 2
 3     private int port;
 4
 5     Server(int port) {
 6         this.port = port;
 7     }
 8     @Override
 9     public void run() {
10         try {
11             ServerSocket serverSocket = new ServerSocket(port);
12
13             InetAddress inetAddress = serverSocket.getInetAddress();
14             System.out.println("server" + inetAddress.getHostAddress());
15             Socket socket = serverSocket.accept();
16             BufferedReader socketInput = new BufferedReader(new InputStreamReader(socket.getInputStream()));
17             BufferedWriter socketOutput = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
18
19             int i = 0;
20             while (true) {
21                 String str = null;
22                 if (!(str = socketInput.readLine()).equals("\n")) System.out.println(str);
23                 System.out.println("server");
24
25                 String NAME = "Server";
26                 socketOutput.write("This msg from " + NAME + " msg num is " + i + " reply to " + str);
27                 socketOutput.write("\n");
28                 i++;
29                 socketOutput.flush();
30             }
31
32 //            socket.shutdownInput();
33 //            socket.shutdownOutput();
34         } catch (IOException e) {
35             e.printStackTrace();
36         }
37
38     }
39 }

测试

 1 public class SocketTest {
 2     public static void main(String[] args) {
 3         byte[] ip = {127, 0, 0, 1};
 4         int port = 27149;
 5         Thread server = new Thread(new Server(port), "server");
 6         server.start();
 7         Thread client = new Thread(new Client(new byte[]{0,0,0,0}, 27149));
 8         client.start();
 9     }
10 }

结果

服务端针对客户端的每条信息都能够进行读取并返回消息给客户端,但是如果注释掉写入换行符,并判断读取是否是换行符的代码,就无法读取到流的结束。

【Java】Java socket通信使用read,readline函数的阻塞问题-LMLPHP

11-30 23:15