Java网络编程 – TCP通信
文章目录
-
- TCP通信
-
- 快速入门(一发一收)
-
- 编写客户端代码
- 编写服务器代码
- 多发多收
- 多发多收(同时接受多个客户端)
- 线程池优化
TCP通信
快速入门(一发一收)
TCP协议回顾:
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(); } } }
多发多收(同时接受多个客户端)
思考: 案例实现了多发多收,那么是否可以同时接收多个客户端的消息?
那么如何才可以让服务端可以处理多个客户端的通信需求?
同时处理多个客户端消息实现架构如下:

实现步骤如下:
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(); } } }
线程池优化
目前的通信架构存在什么问题?
引入线程池处理多个客户端消息的架构如下:

线程池优化多发多收, 我们只需要优化服务器的代码即可:
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
二维码

共有 0 条评论