【网络编程】——基于TCP协议实现回显服务器及客户端

时间:2025-02-22 08:13:06
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TcpEchoServer { private ServerSocket serverSocket = null; private ExecutorService service = Executors.newCachedThreadPool(); // 绑定端口号 public TcpEchoServer(int port) throws IOException { serverSocket = new ServerSocket(port); } // 启动服务器 public void start() throws IOException { System.out.println("服务器启动!!!"); while(true) { // 注意这里和Udp不同的是,Tcp进入循环之后并不是读取客户端请求,而是先处理客户端的连接 // Tcp是一个有连接的协议(Udp是没有连接的协议),所以有连接的话会优先处理连接 // 连接可以理解为客户端和服务器彼此之间保留对方的信息 // 一个服务器要应对很多客户端,在服务器内核中有很多客户端的连接,在应用程序层面我们需要对这些连接进行一一处理 // 这里服务器内核中的连接就像一个一个的待办事项一样,这些待办事项在队列这样的数据结构中 // 所以应用程序需要一一完成这样的任务 Socket clientSocket = serverSocket.accept(); // Thread t = new Thread(() -> { // processConnection(clientSocket); // }); // (); service.submit(new Runnable() { @Override public void run() { processConnection(clientSocket); } }); } } // 通过这个方法来处理连接的逻辑 private void processConnection(Socket clientSocket) { System.out.printf("[%s:%d] 客户端上线啦!!!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort()); // 接下来读取请求,根据请求计算响应,最后再返回响应 // Socket对象内部包含了两个字节流对象,我们需要先获取到这个字节流对象,然后再完成后续的读写操作 try (InputStream inputStream = clientSocket.getInputStream(); OutputStream outputStream = clientSocket.getOutputStream()) { // 一次连接中可以涉及到多次请求和响应 while( true ) { // 第一步:读取请求并进行解析 // 这里为了读取方便,我们直接使用Scanner Scanner scanner = new Scanner(inputStream); if(!scanner.hasNext()) { // 读取完毕客户端下线 System.out.printf("[%s:%d] 客户端下线!!!\n]",clientSocket.getInetAddress().toString(),clientSocket.getPort()); break; } // 这里我们约定客户端输入来的请求是文本数据,同时以空白符作为分割 String request = scanner.next(); // 第二步:根据请求计算响应 String response = process(request); // 第三步:把响应写回给客户端,把OutputStream使用PrinterWriter进行包装,方法进行数据的传输 PrintWriter writer = new PrintWriter(outputStream); writer.println(response); // 刷新缓冲区 writer.flush(); // 打印当前的请求详情 System.out.printf("[%s:%d] req: %s, resp: %s\n",clientSocket.getInetAddress().toString(), clientSocket.getPort(),request,response); } } catch (IOException e) { e.printStackTrace(); } finally { try { clientSocket.close(); } catch (IOException e) { // 这里必须确保Socket能够被关闭 e.printStackTrace(); } } } private String process(String request) { return request; } public static void main(String[] args) throws IOException { TcpEchoServer server = new TcpEchoServer(9090); server.start(); } }