传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,
如果使用了 WireShark 工具,可以看到一次TCP连接建立时的整个过程。
单向通信中,一方固定为信息发送方,另外一方则固定为信息的接收方。
1.1 单向通信中的服务端
服务端即为信息的接收方。
使用 ServerSocket 类创建服务端,并将服务的端口设置为 9527;
serverSocket.accept() 方法用于监听对 9527 端口的连接,该方法为阻塞式方法,当接收到数据后,程序才会继续向下执行,否则一直处于等待状态;
当接收到数据后,因是使用字节流传输,这里使用 使用 InputStreamReader 的转换流将字节数据转换为字符串,并使用 BufferedReader 进行读取和输出;
当服务端接收到客户端的请求后,需要向客户端发出响应数据,使用 PrintWriter 发送响应报文,需要使用 flush() 方法,将消息发出;
当客户端发出的消息为“再见”时,服务端即退出通信,关闭服务。
import java.io.*;import java.net.ServerSocket;import java.net.Socket;public class Server { public static void main(String[] args) { System.out.println("服务器启动!"); try { ServerSocket serverSocket = new ServerSocket(9527); Socket socket = serverSocket.accept(); BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter pw = new PrintWriter(socket.getOutputStream()); System.out.println("接收客户端消息"); while (true){ String in = br.readLine(); System.out.println("接收到客户端发来的请求:" + in); if("再见".equals(in)){ break; } pw.print(in + "回报"); pw.flush(); } } catch (IOException e) { System.out.println("服务启动失败!"); e.printStackTrace(); } }}
启动后,服务端输出为:
服务器启动!
1.2 单向通信中的客户端
客户端即为信息的发送方。
- 创建 Socket 对象,
Socket("localhost", 9527)
和端口为 9527 的服务建立通信; - 接收和发送消息的方法,和服务端相同;
- 为了能够向服务端循环发送消息,使用了死循环,当用户输入“再见”时,终止循环;
- 使用 Scanner 对象接收键盘输入。
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;public class Client { public static void main(String[] args) { try { Socket socket = new Socket("localhost", 9527); //读取输入流 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取输出流 PrintWriter pw = new PrintWriter(socket.getOutputStream()); //从键盘获取输入 Scanner scanner = new Scanner(System.in); while (true){ //从控制台获取向服务端发送的消息 String next = scanner.next(); pw.println(next); pw.flush(); String s = br.readLine(); System.out.println("收到服务器响应:" + s); if("再见".equals(next)){ break; } } } catch (IOException e) { e.printStackTrace(); } }}
1.3 建立通信
启动客户端后,并在客户端的控制台输入“你好”,观察服务端和客户端的控制台
在客户端的控制台输入“再见”,观察服务端和客户端的控制台
双向通信中,双方都可以既是信息的发送方,也可以是信息的接收方。
2.1 双向通信中的服务端
在服务端设置发消息和收消息。
在服务端也使用了 Scanner ,用来接收控制台输入,并将其发送给客户端。
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.util.Scanner;public class Server { public static void main(String[] args) { try{ ServerSocket serverSocket = new ServerSocket(9528); Socket socket = serverSocket.accept(); //获取客户端请求 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取键盘输入 Scanner scanner = new Scanner(System.in); //发送消息到客户端 PrintWriter pw = new PrintWriter(socket.getOutputStream()); while (true){ String input = br.readLine(); System.out.println("收到客户端请求: " + input); String output = scanner.nextLine(); pw.println(output); pw.flush(); if("再见".equals(input)){ break; } } }catch (Exception e){ e.printStackTrace(); System.out.println("服务启动失败!"); } }}
2.2 双向通信中的客户端
在客户端设置发消息和收消息
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.Scanner;public class Client { public static void main(String[] args) { try{ Socket socket = new Socket("127.0.0.1", 9528); //获取服务端响应 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //获取客户端用户输入 Scanner scanner = new Scanner(System.in); //向服务端发送请求 PrintWriter pw = new PrintWriter(socket.getOutputStream()); System.out.println("准备接收请求……"); while (true){ String output = scanner.next(); pw.println(output); pw.flush(); String input = br.readLine(); System.out.println("来自服务端的响应: " + input); if("再见".equals(output)){ break; } } }catch (Exception e){ e.printStackTrace(); } }}
2.3 建议通信
启动服务端及客户端,并在控制台输入内容:
存在的问题:
这样的通信,需要客户端发一次消息 -》 服务端回一次消息,如果客户端同时发送两条消息,就会导致消息不同步。
比如下边的情况:
这个问题可以先思考下,应该如何解决,后边将会给出解决方案。
来源地址:https://blog.csdn.net/QQ156881887/article/details/130351379