TCP版本的 echo server 和 echo client

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • Tcp的api展示
  • 服务端
  • 客户端
  • 存在的问题
  • 解决问题
  • 服务端和客户端的大致流程


前言

上一篇文章我们介绍了UCP的客户端与服务器的一个简单实例,这篇我们简单的来介绍TCP版本的server和client的一个简单交互


Tcp的api展示

TCP版本的 echo server 和 echo client_第1张图片
TCP版本的 echo server 和 echo client_第2张图片

服务端

服务端的要做的流程
1.读取请求
2.根据请求计算响应
3.把响应写回给客户端

下面是完整代码

public class TpcEchoServer {
    //serverSocket就是外场拉课的小哥
    //clientSocket就是内场服务的小姐姐
    //serverSocket只有一个,clientSocket会给每个客户分配一个
    private ServerSocket serverSocket = null;

    public TpcEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    //启动过程
    public void start() throws IOException {
        System.out.println("服务器启动");
        ExecutorService executorService = Executors.newCachedThreadPool();
        //因为我们服务器要反复读取一个服务,所以我们要使用循环
        while (true) {
            Socket clientSocket = serverSocket.accept();
            processConnection(clientSocket);

    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(),
                clientSocket.getPort());
        //try()这种写法种,允许写多个流对象.使用;来分割
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            //我们使用prinwriter把字节流包装秤字符流
            Scanner scanner = new Scanner(inputStream);
            PrintWriter printWriter = new PrintWriter(outputStream);
            while (true) {
                //1.读取请求
                if (!scanner.hasNext()) {
                    //读到流的结尾了.
                    System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress().toString(),
                            clientSocket.getPort());
                    break;
                }
                //直接使用scanner读取一段字符串
                String request = scanner.next();
                //2.根据请求计算响应
                String response = process(request);
                //3.把响应写回给客户端
                printWriter.println(response);
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s; resp : %s\n", clientSocket.getInetAddress().toString(), clientSocket.getPort(), request, response);


            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            clientSocket.close();
        }
    }

    public String process(String request) {
        return request;
    }
    public static void main(String[] args) throws IOException {
        TpcEchoServer tcpEchoServer = new TpcEchoServer(9090);
        tcpEchoServer.start();
    }
}

我针对几个方法具体解释一下.

  private ServerSocket serverSocket = null;
  Socket clientSocket = serverSocket.accept();
  

TCP版本的 echo server 和 echo client_第3张图片
处理代码代码的解释:
TCP版本的 echo server 和 echo client_第4张图片

客户端

客户端的一个流程
1.从键盘上读取用户输入内容
2.讲读取的内容放给服务器
3.从服务器读取响应内容
4.把响应内容显示在控制台上

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIp, int port) throws IOException {
        //这个操作相当于让客户端和服务器建立tcp连接.
        //这里连接上了,socket就会返回
        socket = new Socket(serverIp, port);
    }

    //开始启动客户端
    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream())
        { PrintWriter printWriter = new PrintWriter(outputStream);
            Scanner scannerFromSocket = new Scanner(inputStream);
            while (true){
                //1.从键盘上读取用户输入内容
                System.out.println("->");
                String request= scanner.next();
                //2.讲读取的内容放给服务器
                printWriter.println(request);
                printWriter.flush();
                //3.从服务器读取响应内容
                String response=scannerFromSocket.next();
                //4.把响应内容显示在控制台上
                System.out.printf("req: %s; resp: %s\n", request, response);

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient tcpEchoClient=new TcpEchoClient("127.0.0.1",9090);
        tcpEchoClient.start();
    }
}

存在的问题

这里其实存在一个问题,就是当我们多个客户端去访问服务器的时候,服务端要处理完第一个客户端,在处理第二个客户端,具体看下图.
TCP版本的 echo server 和 echo client_第5张图片

解决问题

先来看看我们针对服务端的处理客户端的请求代码

  public void start() throws IOException {
        System.out.println("服务器启动");
        ExecutorService executorService = Executors.newCachedThreadPool();
        //因为我们服务器要反复读取一个服务,所以我们要使用循环
        while (true) {
            Socket clientSocket = serverSocket.accept();
            processConnection(clientSocket);
        }
    }

改造后的代码
TCP版本的 echo server 和 echo client_第6张图片

  public void start() throws IOException {
        System.out.println("服务器启动");
        ExecutorService executorService = Executors.newCachedThreadPool();
        //因为我们服务器要反复读取一个服务,所以我们要使用循环
        while (true) {
            Socket clientSocket = serverSocket.accept();
            Thread t = new Thread(() -> {
                try {
                    processConnection(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
        }
    }

服务端和客户端的大致流程

TCP版本的 echo server 和 echo client_第7张图片

你可能感兴趣的:(网络编程,tcp/ip)