TCP(Transmission Control Protocol)协议是面向链接的通信协议,即 数据传输之前,先在发送端和接收端建立逻辑链接,然后再传输数据,它提供 了两台计算机之间可靠无差错的数据传输。
TCP通信中必须明确客户端和服务器端,由客户端向服务端发送连接请求 每次连接的创建都要经过三次握手。
三次握手:
第一次握手:客户端向服务端发出连接请求,等待服务器确认。
第二次握手:服务端向客户端回复一个响应,通知客户端收到连接请求
第三次握手:客户端再次向服务端发送确认信息,确认连接 完成三次握手之后,连接建立,客户端和服务端开始进行数据传输,可以 保证数据安全。 数据传输结束以后,断开连接会进行四次挥手。
四次挥手:
第一次挥手:客户端向服务端发送断开连接请求,表示数据发送完毕。
第二次挥手:服务端收到请求后,回复客户端,同意关闭连接的请求。
第三次挥手:服务端向客户端发出断开连接的请求。
第四次挥手:客户端收到服务端请求后,向服务端发送确认信息,服务端接收 到确认信息后断开连接。客户端等待之后没有收到服务端的回复,证明服务端 已正常关闭,客户端也关闭。
发送数据的步骤:
1、创建客户端Socket对象
2、获取输出流,写入数据
3、释放资源
接收数据的步骤:
1、创建服务端的Socket对象
2、监听客户端连接,返回Socket对象
3、获取输入流读取数据
4、释放资源
tcp实现服务端接收多个客户端消息,原理:主线程使用while死循环接收socket连接,为每个客户端的socket通信管道分配一个子线程接收
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(); } } }
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(); } } }