Java Tcp通信
1. TCP通信原理
TCP(Transmission Control Protocol)协议是面向链接的通信协议,即 数据传输之前,先在发送端和接收端建立逻辑链接,然后再传输数据,它提供 了两台计算机之间可靠无差错的数据传输。
TCP通信中必须明确客户端和服务器端,由客户端向服务端发送连接请求 每次连接的创建都要经过三次握手。
三次握手:
第一次握手:客户端向服务端发出连接请求,等待服务器确认。
第二次握手:服务端向客户端回复一个响应,通知客户端收到连接请求
第三次握手:客户端再次向服务端发送确认信息,确认连接 完成三次握手之后,连接建立,客户端和服务端开始进行数据传输,可以 保证数据安全。 数据传输结束以后,断开连接会进行四次挥手。
四次挥手:
第一次挥手:客户端向服务端发送断开连接请求,表示数据发送完毕。
第二次挥手:服务端收到请求后,回复客户端,同意关闭连接的请求。
第三次挥手:服务端向客户端发出断开连接的请求。
第四次挥手:客户端收到服务端请求后,向服务端发送确认信息,服务端接收 到确认信息后断开连接。客户端等待之后没有收到服务端的回复,证明服务端 已正常关闭,客户端也关闭。
2. TCP发送数据
发送数据的步骤:
1、创建客户端Socket对象
2、获取输出流,写入数据
3、释放资源
3. TCP接收数据
接收数据的步骤:
1、创建服务端的Socket对象
2、监听客户端连接,返回Socket对象
3、获取输入流读取数据
4、释放资源
4. TCP通信案例
tcp实现服务端接收多个客户端消息,原理:主线程使用while死循环接收socket连接,为每个客户端的socket通信管道分配一个子线程接收
4.1 服务器端代码
package Tcp通信;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpServer {
public static void main(String[] args) {
try {
// 1.创建服务端的ServerSocket对象,注册端口
ServerSocket serverSocket = new ServerSocket(10086);
System.out.println("----服务端启动成功了----");
// 2.定义一个死循环由主线程负责不断接收客户端的socket管道连接
while (true) {
Socket socket = serverSocket.accept();
// 3.读取客户端发送的消息
ThreadUtil.execute(() -> {
try {
System.out.println("客户端:" + socket.getRemoteSocketAddress() + " 成功连接到服务器");
while (true) {
// 4.从Socket通信管道中得到一个字节输入流
InputStream inputStream = socket.getInputStream();
// 5.把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// 6.按照行读取消息
String message = bufferedReader.readLine();
if (StrUtil.isNotEmpty(message)) {
System.out.println("接收到客户端:" + socket.getRemoteSocketAddress() + ",发送的信息:" + message);
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
// 向客户端发送消息
ThreadUtil.execute(() -> {
try {
System.out.println("请输入发送的信息:");
while (true) {
Scanner scanner = new Scanner(System.in);
String message = scanner.next();
if (StrUtil.isNotEmpty(message)) {
// 2.从Socket通信管道中得到一个字节输出流,负责发送数据
OutputStream outputStream = socket.getOutputStream();
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
// bw.write(message + "\n");
// bw.flush();
// 把低级的字节流包装成打印流
PrintStream ps = new PrintStream(outputStream);
ps.println(message);
ps.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.2 客户端端代码
package Tcp通信;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) {
try {
// 1.创建Socket通信管道请求有服务端的连接,端口号为 10086
Socket socket = new Socket("127.0.0.1", 10086);
System.out.println(socket.getLocalPort() + " :客户端启动成功了");
// 读取服务器发送的消息
ThreadUtil.execute(() -> {
try {
while (true) {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = br.readLine();
if (StrUtil.isNotEmpty(message)) {
System.out.println("接收到服务端:" + socket.getRemoteSocketAddress() + ",发送的信息:" + message);
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
// 向服务器发送消息
ThreadUtil.execute(() -> {
try {
System.out.println("请输入发送的信息:");
while (true) {
Scanner scanner = new Scanner(System.in);
String message = scanner.nextLine();
if (StrUtil.isNotEmpty(message)) {
// 2.从Socket通信管道中得到一个字节输出流,负责发送数据
OutputStream outputStream = socket.getOutputStream();
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
// bw.write(message + "\n");
// bw.flush();
// 把低级的字节流包装成打印流
PrintStream ps = new PrintStream(outputStream);
ps.println(message);
ps.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
4.3 通信测试
4.3.1 启动服务端
4.3.2 启动客户端,服务端显示连接成功
4.3.3 客户端给服务端发送信息,服务端收到信息