Socket(套接字)是计算机底层提供的一种通信技术,支持 TCP 和 UDP 通信,是计算机之间进行通信的协议。
JAVA 实现 socket
需要创建一个客户端和服务端,我们得提前启动服务端,来等待客户端的连接。
JAVA中通过提供 java.net
包来实现 socket。其中我们可以用 net.ServerSocket
来在某个端口上开始服务端,用 net.Socket
来连接到服务端。
在8080端口上建立服务器:
package com;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class socket {
public static void main(String[] args) {
try(ServerSocket server = new ServerSocket(8080)) {
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("客户端已连接, IP地址为:" + socket.getInetAddress().getHostAddress());
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端连接到刚刚创建的服务端:
package com;
import java.io.IOException;
import java.net.Socket;
public class clientsocket {
public static void main(String[] args) {
try (Socket socket = new Socket("localhost", 8080)) {
System.out.println("已连接到服务端");
} catch (IOException e) {
System.out.println("服务端连接失败!");
e.printStackTrace();
}
}
}
使用构造方法连接服务器时构造时就会去尝试连接,也可以使用无参构造,之后调用 socket.connect(new InetSocketAddress("localhost", 8080), 1000)
来连接,1000是指超时时间。
一旦TCP连接建立,服务端和客户端之间就可以相互发送数据,直到客户端主动关闭连接。当然,服务端不仅仅只可以让一个客户端进行连接,我们可以尝试让服务端一直运行来不断接受客户端的连接, 只需要无限循环执行 server.accept()
即可。
使用 socket 进行数据传输
在客户端或服务端通过 Socket
建立连接后,我们就可以让双方发送信息。
例如,让客户端向服务端发送一串字符信息。在客户端需要先通过 socket
获取输出流:
OutputStream stream = socket.getOutputStream();
然后根据 OutputStreamWriter 来输出字符信息而非byte:
System.out.println("请输入要发送给服务器的内容:");
String text = scanner.nextLine();
writer.write(text + '\n'); // 因为服务器那边是用 readline() 来读取,因此需要末尾有换行符
writer.flush();
System.out.println("数据已发送:" + text);
在服务端方面,需要用 BufferedReader 来利用缓冲区读取writer
传入的字符信息:
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println("接收到客户端数据:");
System.out.println(reader.readLine());
socket.close(); // 和服务端TCP连接完成之后,记得关闭socket
设置服务端超时时间
如果我们不希望服务端等待太长时间,可以调用setSoTimeout(int)
来设置IO超时时间,单位为ms。
socket.setSoTimeout(3000);
---
java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.socketRead(SocketInputStream.java:116) at java.net.SocketInputStream.read(SocketInputStream.java:171) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284) at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178) at java.io.InputStreamReader.read(InputStreamReader.java:184) at java.io.BufferedReader.fill(BufferedReader.java:161) at java.io.BufferedReader.readLine(BufferedReader.java:324) at java.io.BufferedReader.readLine(BufferedReader.java:389) at com.test.Main.main(Main.java:41)
开启探测包发送
有时双方有一方会出现意外错误,例如突然断网,导致一方始终持有链接,因此我们可以使用 setKeepAlive(True)
来开启探测包,当对方没有发送任何数据过来,超过一个时间就会发送一个探测包来判断连接是否还有效。
设置 TCP/IP 缓冲区
默认是 8192.
socket.setReceiveBufferSize(25565); //TCP接收缓冲区
socket.setSendBufferSize(25565); //TCP发送缓冲区