Java网络编程 – TCP通信

文章目录

    • TCP通信
      • 快速入门(一发一收)
        • 编写客户端代码
        • 编写服务器代码
      • 多发多收
      • 多发多收(同时接受多个客户端)
      • 线程池优化

TCP通信

快速入门(一发一收)

TCP协议回顾:

TCP通信模式:

Java网络编程 - TCP通信

编写客户端代码

Socket(客户端):

构造器 说明
Socket(String host , int port) 创建发送端的Socket对象与服务端连接,参数为服务端程序的ip和端口。

Socket类成员方法:

方法 说明
OutputStream getOutputStream() 获得字节输出流对象
InputStream getInputStream() 获得字节输入流对象
/**     客户端  */ public class ClientDemo {     public static void main(String[] args) {         try {             // 1. 创建socket通信管道请求与服务端进行连接             /**                 参数一: 服务器IP地址                 参数二: 服务器端口号              */             Socket socket = new Socket("127.0.0.1", 7777);              // 2. 从socket通信管道中获取到字节输出流             OutputStream os = socket.getOutputStream();             // 包裹低级字节输出流为字节打印流             PrintStream ps = new PrintStream(os);              // 3. 打印流发送消息             ps.println("我是TCP的客户端");             ps.flush(); // 刷新         } catch (Exception e) {             e.printStackTrace();         }      } } 

编写服务器代码

ServerSocket(服务端):

构造器 说明
ServerSocket(int port) 注册服务端端口

ServerSocket类成员方法:

方法 说明
Socket accept() 等待接收客户端的Socket通信连接
连接成功返回Socket对象与客户端建立端到端通信
/**     服务器  */ public class ServerDemo {     public static void main(String[] args) {         try {             // 1. 创建ServerSocket对象注册服务器端口             ServerSocket serverSocket = new ServerSocket(7777);              // 2. 调用accept方法, 等待客户端连接, 连接成功返回socket管道对象             Socket socket = serverSocket.accept();              // 3. 从socket管道中获取字节输入流, 完成数据接受             InputStream is = socket.getInputStream();             // 把字节输入流包装为缓冲字符输入流进行消息接收             BufferedReader br = new BufferedReader(new InputStreamReader(is));             // 按照行读取             String message;             if ((message = br.readLine()) != null) {                 System.out.println(message);             }          } catch (Exception e) {             e.printStackTrace();         }      } } 

多发多收

需求

  • 使用TCP通信方式实现:多发多收消息。

具体要求

  • 可以使用死循环控制服务端收完消息继续等待接收下一个消息。
  • 客户端也可以使用死循环等待用户不断输入消息。
  • 客户端一旦输入了exit,则关闭客户端程序,并释放资源。
/**     客户端  */ public class ClientDemo {     public static void main(String[] args) {         try {             Socket socket = new Socket("127.0.0.1", 7777);              OutputStream os = socket.getOutputStream();             PrintStream ps = new PrintStream(os);              // 客户端使用死循环等待用户不断地输入消息             Scanner scanner = new Scanner(System.in);             while (true) {                 System.out.println("发送消息: ");                 String inp = scanner.nextLine();                 // 一旦输入了exit,则关闭客户端程序,并释放资源                 if (inp.equals("exit")) {                     System.out.println("下线成功");                     ps.close();                     break;                 }                 ps.println(inp);                 ps.flush();             }         } catch (Exception e) {             e.printStackTrace();         }      } } 
/**     服务器  */ public class ServerDemo {     public static void main(String[] args) {         try {             ServerSocket serverSocket = new ServerSocket(7777);              Socket socket = serverSocket.accept();              InputStream is = socket.getInputStream();             BufferedReader br = new BufferedReader(new InputStreamReader(is));              String message;             // 死循环控制服务端收完消息继续等待接收下一个消息             while ((message = br.readLine()) != null) {                 System.out.println("收到消息: " + message);             }          } catch (Exception e) {             e.printStackTrace();         }      } } 

多发多收(同时接受多个客户端)

思考: 案例实现了多发多收,那么是否可以同时接收多个客户端的消息?

那么如何才可以让服务端可以处理多个客户端的通信需求

同时处理多个客户端消息实现架构如下:

Java网络编程 - TCP通信

实现步骤如下:

public class ServerReaderThread extends Thread {     private Socket socket;     public ServerReaderThread(Socket socket) {         this.socket = socket;     }     @Override     public void run() {         try {             InputStream is = socket.getInputStream();             BufferedReader br = new BufferedReader(new InputStreamReader(is));              String message;             // 死循环控制服务端收完消息继续等待接收下一个消息             while ((message = br.readLine()) != null) {                 System.out.println("收到消息: " + message);             }         } catch (Exception e) {             e.printStackTrace();         }     } } 
/**     服务器  */ public class ServerDemo {     public static void main(String[] args) {         try {             ServerSocket serverSocket = new ServerSocket(7777);             // 1. 主线程中定义一个死循环由主线程不断地接收客户端socket管道连接             while (true) {                 // 2. 每接收到一个socket管道, 都交给一个独立的子线程负责读取消息                 Socket socket = serverSocket.accept();                 // 交给子线程处理, 并启动子线程                 new ServerReaderThread(socket).start();             }         } catch (Exception e) {             e.printStackTrace();         }      } } 

线程池优化

目前的通信架构存在什么问题

引入线程池处理多个客户端消息的架构如下:

Java网络编程 - TCP通信

线程池优化多发多收, 我们只需要优化服务器的代码即可:

public class ServerReaderRunnable implements Runnable {     private Socket socket;     public ServerReaderRunnable(Socket socket) {         this.socket = socket;     }      @Override     public void run() {         try {             InputStream is = socket.getInputStream();             BufferedReader br = new BufferedReader(new InputStreamReader(is));              String message;             // 死循环控制服务端收完消息继续等待接收下一个消息             while ((message = br.readLine()) != null) {                 System.out.println(socket.getRemoteSocketAddress() + "收到消息: " + message);             }         } catch (Exception e) {             e.printStackTrace();         }     } } 
/**     服务器  */ public class ServerDemo {     // 使用静态变量记录一个线程池对象     private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,             TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),             new ThreadPoolExecutor.AbortPolicy());      public static void main(String[] args) {         try {             ServerSocket serverSocket = new ServerSocket(7777);             while (true) {                 Socket socket = serverSocket.accept();                 System.out.println(socket.getRemoteSocketAddress() + "上线了");                 // 创建Runnable任务交给线程池处理                 pool.execute(new ServerReaderRunnable(socket));             }         } catch (Exception e) {             e.printStackTrace();         }      } } 

线程池优势是什么?

版权声明:本文内容由互联网用户撰写,该文观点仅代表作者本人。本站爱分享仅提供分享服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请立马联系本站,本站将立刻删除。
THE END
分享
二维码
< <上一篇
下一篇>>