TCP编程

引用自JAVA 通过 Socket 实现 TCP 编程

TCP简介

TCP(Transmission Control Protocol传输控制协议)是一种面向 连接的、可靠的、基于字节流 的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层 传输层 所指定的功能,用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上、应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。

应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传输单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失,将会被进行重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

Java Socket简介

socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄。应用程序通常 通过”套接字”向网络发出请求或者应答网络请求

Socket和ServerSocket类库位于java.net包中。ServerSocket用于服务器端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网络连接来说,套接字是平等的,并没有差别,不因为在服务器端或在客户端而产生不同级别。不管是Socket还是ServerSocket,它们的工作都是通过 SocketImpl类机器子类完成的

  • 简单示例:

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class TcpSocketServer {
private int port = 1122;
private ServerSocket serverSocket;

public TcpSocketServer() throws IOException {
serverSocket = new ServerSocket(port, 3);
System.out.println("服务端已启动!");
}

private void service() {
while (true) {
try (Socket socket = serverSocket.accept()) {
System.out.println("建立新的连接,客户端:" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort());
} catch (IOException e) {
e.printStackTrace();
}
}
}

public static void main(String[] args) throws IOException, InterruptedException {
TcpSocketServer server = new TcpSocketServer();
Thread.sleep(20000);
server.service();
}
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class TcpSocketClient {

public static void main(String[] args) throws IOException, InterruptedException {
final int length = 100;
String host = "localhost";
int port = 1122;
Socket[] sockets = new Socket[length];
for (int i = 0; i < length; i++) {
sockets[i] = new Socket(host, port);
System.out.println("第" + (i + 1) + "次连接成功");
}
Thread.sleep(3000);
for (int i = 0; i < length; i++) {
sockets[i].close();
}
}
}

结果:

1
2
3
4
服务端已启动!
建立新的连接,客户端:127.0.0.1:65463
建立新的连接,客户端:127.0.0.1:65464
建立新的连接,客户端:127.0.0.1:65465
1
2
3
4
第1次连接成功
第2次连接成功
第3次连接成功
Exception in thread "main" java.net.ConnectException: Connection refused: connect
  • 多线程示例:

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public class TcpMultiThreadSocketServer {

static class ServerThread extends Thread {
private Socket socket;

public ServerThread(Socket socket) {
this.socket = socket;
}

@Override
public void run() {
InputStream inputStream = null;
InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
OutputStream outputStream = null;
PrintWriter writer = null;
try {
inputStream = socket.getInputStream();
inputStreamReader = new InputStreamReader(inputStream);
bufferedReader = new BufferedReader(inputStreamReader);
String message;
// 循环读取客户端的信息
while ((message = bufferedReader.readLine()) != null) {
System.out.println("客户端 -> 服务端:" + message);
}
socket.shutdownInput();
// 获取输出流,响应客户端的请求
outputStream = socket.getOutputStream();
writer = new PrintWriter(outputStream);
writer.write("欢迎您!");
// 调用flush()方法将缓冲输出
writer.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStreamReader != null) {
inputStreamReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}

}
}

public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(11222);
Socket socket = null;
int count = 0;
System.out.println("服务端启动,等待客户端连接");
while (true) {
socket = serverSocket.accept();
ServerThread serverThread = new ServerThread(socket);
serverThread.start();
count++;
System.out.println("客户端的数量:" + count);
System.out.println("当前客户端IP:" + socket.getInetAddress().getHostAddress());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class TcpMultiThreadSocketClient {

public static void main(String[] args) {
Socket socket = null;
OutputStream outputStream = null;
PrintWriter writer = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
try {
socket = new Socket("localhost", 11222);
// 获取输出流,向服务端发送信息
outputStream = socket.getOutputStream();
writer = new PrintWriter(outputStream);
writer.write("用户名:IsMe");
writer.flush();
socket.shutdownOutput();
// 获取输入流,读取服务端的响应信息
inputStream = socket.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String message;
while ((message = bufferedReader.readLine()) != null) {
System.out.println("服务端 -> 客户端:" + message);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
if (inputStream != null) {
inputStream.close();
}
if (writer != null) {
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

结果:

1
2
3
4
5
6
7
8
9
10
服务端启动,等待客户端连接
客户端的数量:1
当前客户端IP:127.0.0.1
客户端 -> 服务端:用户名:IsMe
客户端的数量:2
当前客户端IP:127.0.0.1
客户端 -> 服务端:用户名:IsMe
客户端的数量:3
当前客户端IP:127.0.0.1
客户端 -> 服务端:用户名:IsMe
1
服务端 -> 客户端:欢迎您!