网络编程UDP+TCP

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

日升时奋斗日落时自省 

目录

1、网络编程基本概念

2、UDP数据报套接字编程

2.1、UDP相关API

2.1.1、DatagramSocket API

2.1.2、DatagramPacket API

 2.2、UDP版本服务器

 2.3、UDP版本客户端

 2.4、UDP连接操作

2.5、翻译业务

2.6、总结

 3、TCP流套接字编程

3.1、TCP相关API

3.2、TCP版本服务器

 3.3、TCP版本的客户端

 3.4、TCP连接操作

3.4.1多线程TCP服务器

3.4.2、线程池TCP服务器


1、网络编程基本概念

网络编程指的是网络上的主机通过不同的进程以编程的方式进行实现网络通信

详细下来就是我们只要满足进程不同就行所以即使是同一个主机只要是不同进程基于网络来传输数据也属于网络编程

1发送端和接收端

发送端数据的发送方进程 称为发送端发送端就是网络通信的源主机

接收端数据的接收方进程 称为接收端接收端就是网络通信中的目的主机

注发送端和接收端只是相对的。

2请求和响应

一般情况获取一个网络资源涉及到两次网络数据传输

首先 请求数据发送

然后响应数据发送

例如 餐馆买饭客人发出请求我要吃什么餐馆针对请求做出处理后厨颠勺中最后做好针对客人进行响应做好了给你

 3客户端和服务端

服务端在常见的网络数据传输场景下把提供服务的一方进程称为服务端可以提供对外服务

客户端获取服务的一方进程称为客户端

注我们常说的客户端发送端和服务器接收端但是理解不单就是客户与服务器交互如果是服务器与服务器交互谁又是客户端发送端其实就是看谁给谁发送请求发送请求的就是发送端接收请求的就是接收端

2、UDP数据报套接字编程

2.1、UDP相关API

基于UDP来编写一个简单的客户端服务器进行网络通信程序需要有一定的网络基础

首先就是要认识进行网络编程要使用的API

核心内容 Socket API操作系统给应用程序提供的网络编程APISocket这里翻译成套接字它是计算机之间进行通信的一种约定或一种方式虽然socket英译为“插座”但是在计算机领域里它叫“套接字”。

可以认为socket API是和传输层密切相关的传输层提供了两个最核心的协议UDP和TCP所以socket也提供了两种风格的API

DatagramSocket使用这个类表示一个socket对象代表socket文件原因在操作系统中把这个socket对象也是当成了一个文件来处理相当于是文件描述符表上的一项提到这里就会想到普通文件也就是对应的硬件设备硬盘socket文件对应的硬件设备网卡一切都是文件而起。

一个socket对象就可以和另外一台主机进行通信如果要和多个不同的主机通信需要创建多个socket对象。

2.1.1、DatagramSocket API

DatagramSocket是UDP Socket用于发送和接收UDP数据报 这里稍微有点绕口多看两遍

这个绕口的话是解释DatagramSocket与下面马上要提到DatagramPacket对比理解实际意思就是DatagramSocket里面是数据报作为参数也就是DatagramPacket类的它就是作参数的

1无参数版本的构造方法没有指定端口系统会自动分配一个空闲的端口

 2一个参数版本的构造方法有一个端口号此时就是为了socket对象能和指定的端口号简单的数字范围在1024-65535之间关联起来我们知道端口号是和进程相关连的为了确定是哪个进程本质上不是进程和端口号建立联系而是进程中的socket对象和端口建立了联系

3需要了解的方法 一个receive接收另一个是send发送

 receive方法此处有一个DatagramPacket的参数但是这里填的相当于是一个空对象receive方法内部会对参数的这个空对象进行内容填充将接收来的数据填充从而构造出结果数据参数也是一个“输出型参数”  如果没有接收到数据 会进行阻塞等待

send方法也有一个DatagramPacket参数这里的参数就有数据了从此套接字发送数据报

 最后一个使用需用方法就是close 关闭此数据报套接字

2.1.2、DatagramPacket API

DatagramPacket是UDP socket发送和接收的数据报

DatagramPacket表示UDP中传输的一个报文构造这个对象可以指定一些具体的数据进去这些数据后面实现UDP的时候会展示

12个参数版本的构造方法

把buf这个缓冲区给设置进去数据存储先放在缓存区上既然是文件就需要涉及到文件操作当然内部会自己处理我们直接使用网络编程相关API就可以了最后一个参数是缓冲区设置的长度

24个参数版本的构造方法

 构造缓冲区、起始位置、缓冲区长度、地址这个地址包括两个内容IP地址 和 端口号port

这里提到一个InetSocketAddress 的API 它也有自己得构造方法里面包含两个参数一个IP地址另一个是端口号

 2.2、UDP版本服务器

我们这里做的是自己本机电脑的服务器就是本机连接本机 称为回显服务器echo server

一个普通的服务器的构造需要涉及这几步收到请求根据请求计算响应返回响应

Echo server 省略了其中的“根据请求计算响应”实现的这个程序是请求啥返回啥主要针对socket API基本用法的理解这里不写“请求计算响应”不是它不重要它是最重要的但是实现需要对应的业务这个等socket会用了再实现一个比较简单业务给友友们理解

提示我们这里自定义了一个类 叫做 UdpEchoServer 以下UDP服务器代码都是包含在这个类中

第一步

网络编程操作本身就是操作网卡的但是网卡不方便直接操作在操作系统内核中使用了一个特殊的叫做“socket”这样的文件来抽象表示网卡因此进行网络通信是势必要有一个Socket

private DatagramSocket socket=null;

第二步

 这里是我们自己实现一个UDP版本的服务器socket当前置空的原因是为了在该类的构造方法中添加输入自己的端口号创建socket对象的同时给他绑定一个端口号

public UdpEchoServer(int port) throws SocketException {
        //构造方法中有一个参数就是 端口号 在socket创建对象的时候传入端口号
        socket=new DatagramSocket(port);
    }

为什么要关联一个具体端口号

因为客户端是需要通过服务器的端口号来给服务器发送请求那前面不是说如果不分配的话操作系统会分配一个随机的端口号吗如果是这样的话客户端就不知道这个端口号是什么了也就没有办法进行通信了。

第三步

思路:
(1)创建一个执行start方法,因为客户端肯定是不会就发发送一次请求的,会有多次,所以服务器一般都是7*24小时工作的,这里会写一个while(true)循环保持服务器不会断开.

(2)那循环内需要的就是网络所需的基础 : 接收请求 , 根据请求计算响应  ,  返回响应(这里我们细说)

接收请求:

针对UDP来说传输数据的基本单位是"数据报" 对应的类就是DatagramPacket,首先就是读取客户端的请求,需要使用receive方法 ,该方法的参数是一个输出型参数,这个参数就要是一个空的DatagramPacket对象,需要DatagramPacket对象创建对象

 DatagramPacket对象中传了两个参数 ,一个缓冲区,另一个该对象缓冲区的的长度;创建对象后传参给receive,如果客户端有数据传入receive内部会针对参数对象填充数据(该数据来自网卡),如果客户端没有数据传入receive会进行阻塞

 根据请求计算响应:

此时DatagramPacket是一个特殊的对象,并不直接进行数据处理,可以把来面的数据转化为字符串进行处理

获取字符串之后,就可以进行处理了(这里获取字符串的原因就是为了便于我们做处理);

 因为我们这里是走一下流程,所以没有写请求处理,知道要写这个就行.

返回响应:

把响应写回客户端,使用方法 send的参数也是DatagramPacket 对象,需要把返回对象构造好,此处构造对象就不在是空字节数了,而是使用响应数据来构造的

 到了这里UDP的客户端就写完了.(以上都是图片方便看解析,下面附有代码)

public void start() throws IOException {
        System.out.println("服务器启动");
        //服务器不是只给一个客户端提供服务系统就完了一定会有很多的客户端
        while(true){
            /*
            * 只要客户端来了就提供服务
            * 1、读取客户端发来的请求是啥
            * receive 方法的参数是一个输出型参数 需要先构造一个空白的DatagramPacket对象 交给receive来进行填充
            * */
            DatagramPacket requestPacker=new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacker);  //将接受传来的数据放入的当前的缓冲区
            //此时这个 DatagramPacket 是一个特殊的对象 并不方便直接进行处理 可以把这里包含的数据拿出来构造成一个字符串
            String requset =new String (requestPacker.getData(),0,requestPacker.getLength());
            //2、根据请求计算响应 由于此处是回显服务器 响应和请求相同
            String response=process(requset);
            /*
            * 3、把响应写回到客户端 send的参数也是 DatagramPacket 需要把这个 Packet对象构造好
            * 此处构造的响应对象 不能是用空的字节数 构造了而是要使用响应数据来构造
            * */
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacker.getSocketAddress());
            socket.send(responsePacket);
            //4、打印一下 当前这次请求响应处理中间结束
            System.out.printf("[%s: %d] req:%s ,resp:%s\n",responsePacket.getSocketAddress().toString(),
                    responsePacket.getPort(),requset,response);
        }
    }
    public String process(String requset) {
        return requset;
    }

最后一行还进行了打印,这里也对其进行解释:

 main方法操作

 2.3、UDP版本客户端

这里的客户端是为了连接上面的服务器待这里客户端写好以后友友们就可以自行尝试。

提示这里客户端创建一个自定义类我这里叫做 UdpEchoClient 以下所有UDP客户端代码都在这个类中

第一步
创建我们需要的变量 UDP客户端也需要socket文件来传输数据 需要创建一个 socket对象同时还要知道服务器的IP地址和 端口号才能发送数据。

    private DatagramSocket socket=null;
    private  String serverIP=null;
    private  int serverPort=0;
    /*
    * 一次通信 需要有两个 IP 两个端口
    * 客户端 IP 是 127.0.0.1
    * 客户端的 port 是系统自动分配的
    * 服务器 IP 和 端口 也需要告诉客户端 才能顺利把这个消息发给服务器
    * */
    /*
    * 客户端这里为啥没有 个一个具体的端号  因为服务器不是本机 客户的主机上可能已经运行了很多的程序就会导致你设置的端口 号是被重复会产生冲突
    * */
    public  UdpEchoClient(String serverIP ,int serverPort) throws SocketException {
        socket=new DatagramSocket();
        this.serverIP=serverIP;
        this.serverPort=serverPort;
    }

这里可能会有友友们问到为啥服务器有自己自己的端口号这里为什么没有提到客户端具体的端口号

答案客户端的端口号是系统自动分配的分配一个空闲的端口号那可以自己给客户端定义一个具体的端口号吗勉强可以因为客户端上有可能有很多程序每个程序都有自己的端口号如果自己定义就可能会产生冲突

举个例子你去吃饭人多的时候就会给你一个牌牌叫到你你来领餐但是此时你就是想要66号牌牌但是可能这个牌牌已经被人领走了该饭店就是一个客户端餐牌就是端口号客户端会系统自动分配端口号你强行要一个餐牌就可能已经被其他程序拿走了造成冲突

第二步

写一个start方法进行运行 思路服务器大同小异反向操作

 whiletrue循环中执行写数据进行判断结束、发送数据、接收数据、控制台打印

写数据进行判断

 发送数据

 接收数据

 控制台打印

 以上图片解析比较零散以下附有以上解释的代码

public void start() throws IOException {
        System.out.println("客户端启动 ");
        Scanner scanner=new Scanner(System.in);
        while(true){
            //1、从控制台读取发送的数据
            System.out.println("> ");
            String request=scanner.next();
            if(request.equals("exit")){
                System.out.println("结束");
                break;
            }
            /*
            * 2、构造成UDP 请求 并发送
            *   构造这个Packet 的时候 需要把serverIP 和 port 都传入过来 但是此处IP地址是一个32位的二级制的整数
            *   上述的IP地址是一个字符串 需要使用 InetAddress.getByName来进行一个转换
            * */
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIP),serverPort);
            socket.send(requestPacket);
            //3、读取服务器的UDP 响应 并解析
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            //4、把解析好的结果显示出来
            System.out.println(response);
        }
    }

main方法操作

和UDP服务器操作基本相同但是需要 服务器的IP地址和服务器的端口号

 2.4、UDP连接操作

首先这里先说怎么检测你的服务器和客户端都是写好的可以运行了

以上连接操作是怎么进行代码详细分解

2.5、翻译业务

以下带有业务的服务器继承了上面UDP版本服务器进行的

    //字典服务器 用来继承既可以
    //DictServer 来说 和 EchoServer 相比 大部分的东西都是一样的
    //主要是请求计算机响应是不一样的
public class UdpDictServer extends  UdpEchoServer {
    //这里是一个简单的翻译  使用到了Map  第一个泛型参数是接收单词 第二个泛型参数是 翻译过来的汉语
    private Map<String ,String> dict=new HashMap<>();
    //应用服务器这里需要继承父类 构造方法里面就可以写对应的东西
    public UdpDictServer(int port) throws SocketException {
        super(port);
        /*
        * 给当前 继承服务器 设置内容
        * 此处可以无限键值对  以下就是翻译内容 当然这里只是为了方便友友们看 实际自己想实现点简单的业务也是可以的
        * */
        dict.put("cat","小猫");
        dict.put("dog","小狗");
        dict.put("fuck","卧槽");
    }
    //继承了也就需要 重写 UdpEchoServer的方法
    public String process(String request){
        //查词典的过程
        return dict.getOrDefault(request,"当前单词没有查到结果");
        //这里就是 看是否是默认值 , 如果有就是用当前值 如没有的话就是用默认值
    }
    public static void main(String[] args) throws IOException {
        //本次只需要掉用该服务器就可以了
        UdpDictServer server=new UdpDictServer(9090);
        server.start();
    }
}

这里就是简单的业务实现上面给了注释代码不多也很好理解重点理解前面的服务器和客户端代码这里就不难看懂了。

以下演示以下该带有业务的服务器跑起来 与客户端 联用

2.6、总结

1服务器的端口 是固定指定的目的是为了方便客户找到服务器程序

服务器是我们自己手里的机器上面运行啥都是我们控制的指定安排空闲端口即可

从哪里看 可以有两个地方看 任务管理器友友们应该都很熟悉Ctrl+alt+del 后点击任务管理器以下点击就能查看PIDProcess ID其实是进程号也是独一无二的

 另一种方法就是命令行查看 涉及cmd命令 netstat -ano  (命令行打开操作 win+r 弹出框输入cmd)

 这里只截取了一部分作为演示能理解就行

2客户端的端口 是由系统分自动分配的如果手动指定可能能会造成其他程序的端口的冲突

客户端上的程序是不可控的系统分配是最好的服务器上的端口号是可控的因为程序员可以自己看见或者自查

3端口冲突

端口冲突会有以下提醒 这里以服务器作为当前的端口冲突来解释

上面已经提及了两个服务器一个UPD版本的服务器另一个翻译业务的服务器 两个服务器同时用一个9090端口号就会产生冲突

 3、TCP流套接字编程

3.1、TCP相关API

TCP API主要涉及两个类

ServerSocket 专门给服务器使用的Socket对象 

Socket 是既能给 客户端是用也能给服务器使用 知道这里不是很好理解往后面看结合代码理解

TCP和UDP传输数据不一样 UDP是“数据报” 但是TCP不是 而是以“字节”的方式 流式传输

ServerSocket一个参数构造方法

 创建一个服务器套接字Socket并绑定到指定端口

使用方法就有所变化 检测方法Socket.accept()开始监听指定端口有客户端连接后返回一个服务端Socket对象并基于该Socket建立与客户端的连接 否则阻塞等待 这里明显与UDP的服务器不同了体现了TCP的有连接的特性

关闭此套接字 close()方法

这里相当于是连接看是否连接上客户端TCP 有一个特性就是有连接的例如电话一样需要有人接所以这个accept就是监听有没有人接电话没有的话就先进行阻塞这里只是以电话举例不是说电话就是这么搞的

Socket在服务器这边是由accept返回的在客户端这边咱们代码里构造的时候制定了一个IP地址和端口号有了这两个信息就能和服务器建立连接了。

既然是以字节的方式进行传输的那就会涉及到IO文件操作 InputStream对应getInputStream方法和OutputStream对应的getOutputStream方法 进一步通过Socket对象获取到内部的流对象借助流对象来进行发送接收

3.2、TCP版本服务器

提示这里需要我们自定义一个类叫做TcpEchoServer来写TCP版本服务器的代码

第一步就是创建一个ServerSocket 对象 创建一个构造方法进行传参一个具体的端口号

//相当于是  接收客户来
    private ServerSocket serverSocket=null;
    public  TcpEchoServer(int port) throws IOException {
        //传入一个端口号
        serverSocket =new ServerSocket(port);
    }

 第二步那服务器ServerSocket对象已经创建好了需要一个方法来进行服务器start方法

public void start() throws IOException {
        System.out.println("启动服务器");
        while(true){
            //使用这个 clientSocket 和 具体的的客户端进行交流
            //具体进行服务器  这里用作监听 客户端是否上线
            Socket clientSocket =serverSocket.accept();
            //如果上线  accept方法 阻塞结束 进行连接操作
            processConnection(clientSocket);
        }
    }

每次创建或者返回一个 Socket对象 Socket就是文件每次创建一个clientSocket对象就要占用一个文件描述符表使用完毕之后就会进行“释放” 但是不建议直接在这里“释放”在finally里面“释放”

到了这里就会友友问 ServerSocket 与Socket都是创建对象这不是多此一举吗答案这里其实我也不知道凡是存在必有道理我们先按照这样的方法来。

但是这里还是要说一下这里该如何理解。

 第三步processConnection如何来连接客户端操作

思路

1可以显示一下 因为已经接收到了客户端 那这里打印一次客户端已上线

2Socket返回套接字输入流返回套接字输出流因为TCP是流式操作的

3处理肯定不是一个请求和响应所以需要循环操作之后读取请求判断请求数据是否存在不存在那连接也就断开了 如果存在跳过即可进行数据输入

4根据请求构造响应

5这里返回响应结果想要是一个字符串但是接收来的是字节流 需要 稍作转换转换成字符串

 6服务器打印

 以下是附上processConnection代码

 private void processConnection(Socket clientSocket) {
        System.out.printf("[%s:%d] 客户端上线 \n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //基于上述socket 对象和 客户端 进行通信
        //以下使用 try 是java语法 try with resources
        try (InputStream inputStream=clientSocket.getInputStream();
             OutputStream outputStream=clientSocket.getOutputStream()){
            //由于要处理多个请求和 响应 也是使用 循环进行的
            while(true){
                //1、读取请求
                Scanner scanner=new Scanner(inputStream);
                if(!scanner.hasNext()){
                    System.out.printf("[%s:%d]客户端下线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                    break;
                }
                //注意 此处使用next 是一直 读取到换行符 或者 空格 或者 其他空白字符tab 但是 最终返回结果里不包含前面提到的这几个类别
                String request=scanner.next();
                //2、根据请求构造响应
                String response=process(request);
                //3、返回响应结果
                //OutputStream 没有write String功能 这里需要转换 可以把String 里的字节数组转换出来 进行写入
                //也可以用字符流来转化一下
                PrintWriter printWriter=new PrintWriter(outputStream);
                //此处使用 println来写入 让结果带有一个 \n 换行 方便对端来接收解析
                printWriter.println(response);
                //前面IO文件操作 中知道在字符写文件的时候 是需要刷新的所以这里也会进行
                printWriter.flush();

                System.out.printf("[%s:%d] req:%s ,resp :%s \n",clientSocket.getInetAddress().toString(),clientSocket.getPort()
                ,request,response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                //此处需要处理一下
                clientSocket.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
 public String process(String request) { //这里也只是走个过程并没有真的对请求进行处理
        return request;
    }

 main方法操作

 3.3、TCP版本的客户端

提示自定义一个TCPEchoClient类 以下TCP客户端代码都在该类中 

如果友友们从前面看到这里了基本不管是创建服务器还是创建一个客户端都是创建Socket对象TCP客户端代码就没有TCP服务器代码麻烦了。

1创建Socket对象 写一个构造方法接收服务器的IP地址和 端口号

//定义一个Socket对象用来接收 IP地址和 端口号
    private Socket socket=null;

    public TcpEchoClient(String serverIp ,int serverPort) throws IOException {
        //Socket构造方法 能够识别点分十进制格式的 IP地址 比DatagramPacket更方便
        //new 这个对象的同时 就会进行TCP连接操作
        socket=new Socket(serverIp,serverPort);
    }

2写一个客户端启动start方法

客户端:用户写入数据、接收套接字输入流和输出流、连接结束的判断 、数据发送、接收数据

此处就不在详细解释了基本和以上代码相似代码配有详细的注释

public void start(){
        System.out.println("客户端启动");
        Scanner scanner=new Scanner(System.in);
        //接收套接字的输入流 和 输出流
        try(InputStream inputStream=socket.getInputStream();
            OutputStream outputStream=socket.getOutputStream()){
            while(true){
                System.out.println(">");
                //1. 先从键盘上读取用户数据内容
                String request=scanner.next();
                //判定输入一个算是解除连接  我们这里给了一个exit 表示结束连接 就相当于是 挂电话的按键
                if(request.equals("exit")){
                    System.out.println("goodbye");
                    break;
                }
                //2 把读到的内容构造请求发送给服务器  这里和TCP服务器是一样的 都需要进行转换将字节转化为字符串
                PrintWriter printWriter=new PrintWriter(outputStream);
                //发送给服务器 printWriter 的 println方法本身就会起到发送的作用
                printWriter.println(request);
                //此处需要刷新缓冲区 确保数据是发出去了
                printWriter.flush();
                //3 服务器的响应    Scanner本身就参数就是字节输入流参数
                Scanner respScanner=new Scanner(inputStream);
                //进行读取
                String response=respScanner.next();
                //4 把响应内容显示到界面上
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

代码执行作以下分析

以上代码是写完了但是这里还有几个想要提醒要点

1疑惑其中使用了printWriter类来转换字节流变成字符串是否还是同一个文件描述符表OutputStream相当于一个文件描述符socket文件通过OutputStream就可以往这个 文件描述符表中写入数据但是当前的OutputStream自身方法不方便 写字符串需要进行转换 PrintWriter对象来表示对应的是同一个文件描述符表

2以上能看发送是通过PrintWriter类中println方法进行发送的细节问如果不用println直接用print发送行不行

答案不行图解

 3.4、TCP连接操作

 连接之后就发现问题了不能多个客户端进行连接如何解决呢答案多线程

3.4.1多线程TCP服务器

以前面的TCP服务器作为地基 这里有start方法内部需要稍作修改即可

 public void start() throws IOException {
        System.out.println("启动服务器");
        while(true){
            //使用这个 clientSocket 和 具体的的客户端进行交流
            //具体进行服务器  这里用作监听 客户端是否上线
            Socket clientSocket =serverSocket.accept();
            //如果上线  accept方法 阻塞结束 进行连接操作
            Thread thread=new Thread(()->{
                processConnection(clientSocket);
            });
            thread.start();
        }
    }

为什么多线程操作加在这里不用过多的解释那多线程为什么不包含以下的代码呢

Socket clientSocket =serverSocket.accept();

 这里在while循环中所以每次多线程执行并且在当前while循环中结束再进行下一次while循环

 多线程已经能解决问题了但这里还不打算演示因为我们的客户端最多也就只能开几个确实带的动C10K1w客户端问题解决了但是如果更多呢C10M1kw客户端问题呢创建或者销毁这么多线程也是要有开销的多线程提到开销问题优化措施就会想到线程池。

3.4.2、线程池TCP服务器

修改多线程修改代码位置相同

public void start() throws IOException {
        System.out.println("启动服务器");
        //创建线程池  这里创建的不是固定数量线程的池子 是根据工作需要创建的线程池
        ExecutorService service=Executors.newCachedThreadPool();
        while(true){
            //使用这个 clientSocket 和 具体的的客户端进行交流
            //具体进行服务器  这里用作监听 客户端是否上线
            Socket clientSocket =serverSocket.accept();
            //如果上线  accept方法 阻塞结束 进行连接操作
            //提交任务
           service.submit(()->{
               processConnection(clientSocket);
           });
        }
    }

 这里就没有什么过多的解释了如果对线程池不是很理解的友友可以看下这篇博客

现在演示使用多线程之后客户端有怎么样的结果

 注 TCP版本服务器和客户端没有写相关业务友友们可以模仿这UDP翻译业务也给TCP写一个基本是一样的写法这里再TCP版本中就不在重复进行了。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6