• TCP协议常用API以及实现TCP客户端服务端


    目录

    TCP常用API

    ServerSocket 

    Socket 

    TCP服务端(单线程) 

    属性+构造方法:

    代码编写 

    TCP客户端(单线程) 

    属性+构造方法 

    代码编写 

    单线程TCP客户端—服务端通信结果 

    单线程TCP存在的问题 

    TCP服务端(支持多个客户发送请求) 

    多线程版本服务端 

    线程池版本服务端   

    关于TCP的长连接和短连接 

    短连接工作过程 

    长连接工作过程 


    TCP常用API

    ServerSocket:专门给服务端使用的socket。 

    Socket:既可以提供给客户端使用,也可以给服务端使用。 

    ServerSocket 

    构造方法:

    方法签名方法说明
    ServerSocket(int port)创建一个服务端嵌套字,并且指定服务端所占用的进程

    成员方法 accept: 

    方法签名方法说明
    Socket accept()

    TCP是"有连接"的协议,TCP客户端与服务端一定要建立连接,才可以互相发送消息。因此这个accept方法,返回的socket对象,服务端就是通过这个socket对象和客户端进行通信的。

    如果服务端没有收到socket对象,那么就会阻塞等待,无法进行通信。

    Socket 

      对于服务端来说,是由accept()方法返回的的,返回的socket对象用于和客户端进行通信。 

    构造方法 :

    对客户端来说,构造方法构造对象时需要指定ip地址和端口号,这个ip和端口号是服务端的 

      

    两个普通常用的方法: 

    方法签名方法说明
    getInputStream()通过socket对象,获取到内部的输入流对象
    getOutputStream()通过socket对象,获取到内部的输出流对象

    TCP服务端(单线程) 

    属性+构造方法:

           需要在TcpEchoServer内部封装一个属性,这个属性是ServerSocket。

           在构造方法当中,需要指定ServerSocket占用哪个端口号,此端口号就是服务端的端口号

    代码编写 

    1. import java.io.IOException;
    2. import java.io.InputStream;
    3. import java.io.OutputStream;
    4. import java.io.PrintWriter;
    5. import java.net.ServerSocket;
    6. import java.net.Socket;
    7. import java.util.Scanner;
    8. public class TcpEchoServer {
    9. /**
    10. * 用于TCP客户端和服务端通信的socket对象
    11. */
    12. private ServerSocket serverSocket;
    13. /**
    14. * 构造方法指定服务端所占用的端口号
    15. */
    16. public TcpEchoServer(int port) throws IOException {
    17. serverSocket=new ServerSocket(port);
    18. }
    19. /**
    20. * 启动服务端
    21. */
    22. public void start() throws IOException {
    23. System.out.println("启动服务端!");
    24. while(true){
    25. //使用clientSocket与客户端交流
    26. Socket clientSocket=serverSocket.accept();//1、接收客户端发送的socket
    27. processConnection(clientSocket);//2、处理客户端的连接
    28. }
    29. }
    30. /**
    31. * 处理客户端发送来的连接
    32. * 客户端发送来的连接:clientSocket
    33. */
    34. public void processConnection(Socket clientSocket) throws IOException {
    35. //输出客户端ip地址和端口号
    36. System.out.println("客户端已上线!客户端的IP是:"+clientSocket.getInetAddress()+
    37. "客户端的端口号是:"+clientSocket.getPort());
    38. //2-1、读取clientSocket中的输入输出流对象
    39. InputStream inputStream=clientSocket.getInputStream();
    40. OutputStream outputStream=clientSocket.getOutputStream();
    41. //使用while循环处理多个请求和响应
    42. while (true){
    43. //2-2、通过Scanner来获取输入流
    44. Scanner scanner=new Scanner(inputStream);
    45. //读取完毕直接返回
    46. if(!scanner.hasNext()){
    47. System.out.println("客户端已经下线!客户端的IP是:"
    48. +clientSocket.getInetAddress()+
    49. ";客户端的端口是:"+clientSocket.getPort());
    50. //退出循环
    51. break;
    52. }
    53. //2-3、根据请求计算响应
    54. String request=scanner.next();
    55. //构造回写内容
    56. String response="服务器已经响应:"+request;
    57. //2-4、使用PrintWriter发送OutputStream
    58. PrintWriter printWriter=new PrintWriter(outputStream);
    59. printWriter.println(response);
    60. //刷新缓冲区保证能够发送出去
    61. printWriter.flush();
    62. }
    63. //2-5、关闭连接
    64. clientSocket.close();
    65. }
    66. public static void main(String[] args) throws IOException {
    67. TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);
    68. tcpEchoServer.start();//服务端启动
    69. }
    70. }

    TCP客户端(单线程) 

    属性+构造方法 

    需要在TcpEchoClient中加入Socket指定服务端的Ip地址和端口号

    1. import java.io.IOException;
    2. import java.net.Socket;
    3. public class TcpEchoClient {
    4. //客户端属性socket指定服务端IP+端口号
    5. private Socket socket;
    6. public TcpEchoClient(String serverIp,int port) throws IOException {
    7. socket=new Socket(serverIp,port);
    8. }
    9. }

    TCP是有连接的,所以要想使客户端和服务端可以通信就需要先建立连接,这里的socket对象创建时就说明客户端和服务端成功建立了连接。 

    客户端的socket创建完成的瞬间,服务端的accept方法就会立即接收到客户端的socket对象。 

    代码编写 

    1. import java.io.IOException;
    2. import java.io.InputStream;
    3. import java.io.OutputStream;
    4. import java.io.PrintWriter;
    5. import java.net.Socket;
    6. import java.util.Scanner;
    7. public class TcpEchoClient {
    8. //客户端属性socket指定服务端IP+端口号
    9. private Socket socket;
    10. public TcpEchoClient(String serverIp,int port) throws IOException {
    11. socket=new Socket(serverIp,port);
    12. }
    13. //启动客户端
    14. public void start() throws IOException {
    15. System.out.println("客户端已上线!");
    16. //1、利用socket获取到与服务端进行数据交互的输入输出流(inputStream和outputStream)
    17. Scanner input=new Scanner(System.in);
    18. InputStream inputStream = socket.getInputStream();
    19. OutputStream outputStream=socket.getOutputStream();//都是相对于客户端来进行输入/输出操作的。
    20. while(true){
    21. //2、从控制台获取用户输入的信息
    22. System.out.println("输入你想要发送的信息:");
    23. String request=input.next();
    24. //3、将获取到的request通过流的方式发送给服务端
    25. PrintWriter printWriter=new PrintWriter(outputStream);
    26. printWriter.println(request);
    27. printWriter.flush();//刷新缓冲区
    28. //4、通过Scanner读取服务端响应并进行回显
    29. //读取服务端响应
    30. Scanner scanner=new Scanner(inputStream);
    31. String response=scanner.next();
    32. //响应内容回显到界面
    33. System.out.println(response);
    34. }
    35. }
    36. public static void main(String[] args) throws IOException {
    37. TcpEchoClient tcpEchoClient=new TcpEchoClient("127.0.0.1",9090);
    38. tcpEchoClient.start();//启动客户端
    39. }
    40. }

    单线程TCP客户端—服务端通信结果 

     

    单线程TCP存在的问题 

    当服务端启动之后,如果有客户端与服务端建立连接,服务端的accept方法就会返回一个socket对象,之后再通过processConnection方法对该客户端的socket不断进行while循环进行处理,调用scanner.next()方法,也就是说只要该客户端不下线,服务端就会一直在这个循环中,这将导致其他的想要建立连接的客户端无法完成。

    当然,不使用while循环也是不可以的,因为如果没有while循环,客户端发送一次请求,服务端就会把连接给断掉,如果这个客户端还想继续建立连接,就需要重新建立连接,重新创建Socket对象,但是上述代码中的客户端只能创建一次socket,所以这时候就无法再建立连接了。

    要想解决这个问题,就需要TCP服务端支持多线程进行操作。

    TCP服务端(支持多个客户发送请求) 

    支持多个客户发送请求用到多线程的知识,可以提供多线程版本的服务端和线程池版本的服务端

    多线程版本服务端 

    服务端的核心在于处理多个客户请求,也就是processConnection方法需要支持多线程,也就是说每个客户端的请求都会有一个线程进行处理。

    多线程版本的服务端在客户端连接少的情况下是合适的,但是当客户端连接的量比较大的时候就不合适了,会有大量的线程的创建和销毁,资源耗费比较严重,所以可以考虑使用线程池来处理processConnection()方法。

    线程池版本服务端   

     

    关于TCP的长连接和短连接 

    短连接工作过程 

    1、客户端与服务端建立连接

    2、客户端向服务端发送请求

    3、读取响应

    4、关闭连接 

    特点:短连接一次通信一次连接,下一次通信需要重新建立连接,一次通信只会建立一次连接

    长连接工作过程 

    1、客户端与服务端建立连接

    2、客户端向服务端发送请求

    3、读取响应

    4、可根据需求再次发送请求(也是回到2)

    5、重复2-4之间若干次,再决定是否关闭连接 

    特点:一次连接可多次发送请求,长连接的复用性更高 

  • 相关阅读:
    换掉ES!Redis官方搜索引擎来了,性能炸裂!
    漏洞扫描系统的主要功能有哪些
    MinDoc文档管理系统在宝塔环境安装教程
    面对无代码开发的局限性,我们该如何应对
    kali安装volatility及插件mimikatz
    AI实战营第二期 第十节 《MMagic 代码课》——笔记11
    设计模式:简单工厂模式(C#、JAVA、JavaScript、C++、Python、Go、PHP):
    跨域问题总结
    【2022黑马程序员】Mysql索引总结
    Python中Mock和Patch的区别
  • 原文地址:https://blog.csdn.net/m0_67995737/article/details/136292974