Java千百问_02基本使用(012)_如何编写多线程Socket程序
来源:互联网 发布:手机数据恢复软件安卓 编辑:程序博客网 时间:2024/05/22 03:41
点击进入_更多_Java千百问
1、如何编写多线程Socket程序
了解Socket看这里:Socket是什么
多线程Socket与单线程类似,只是使用了多线程的方式来管理连接,主线程负责接收连接,在接到连接后变创建新的线程,每个线程负责与自己的客户端进行通信。
了解单线程Socket看这里:如何编写单多线程Socket程序
与单线程Socket例子相比来说,服务端可以与多个客户端进行通信了,不过多线程频繁的创建与销毁便会带来很大的资源开销,而系统的网络资源等都是有限的。因此一般会引入线程池,可以在某种程度上重用线程,减少线程的创建和销毁的次数以减少开销。
我们的代码也分为客户端和服务端两部分。服务端的代码中包含了使用和不使用线程池的两种方式。
服务端代码:
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class SocketThreadPoolDemoServer { private int port = 8000; private ServerSocket serverSocket; private ExecutorService executorService; // 连接池 private final int POOL_SIZE = 1; // 连接池大小 , 若为 1 时最多支持 2 线程 public SocketThreadPoolDemoServer() throws Exception { serverSocket = new ServerSocket(port); executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);// 初始化线程池 System.out.println("waitting connet..."); } /** * * 接受连接 * * @author sunjie at 2016年6月14日 * */ public void service() { Socket socket = null; while (true) { try { socket = serverSocket.accept(); executorService.execute(new Handler(socket)); // 使用连接池 // new Thread(new Handler(socket)).start();// 不使用连接池 } catch (IOException e) { e.printStackTrace(); } } } /** * * 线程类,负责维持与一个客户端的通信 * * @author sunjie at 2016年6月14日 * */ class Handler implements Runnable { private Socket socket = null; public Handler(Socket socket) { this.socket = socket; } @Override public void run() { System.out.println("new connection accepted:" + socket.getInetAddress() + ":" + socket.getPort()); try { BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); PrintWriter writer = new PrintWriter(socket.getOutputStream()); String msg = null; while ((msg = reader.readLine()) != null) { System.out.println("from " + socket.getInetAddress() + ":" + socket.getPort() + ", receive msg:" + msg); writer.println(msg); writer.flush(); if ("close".equals(msg)) { break; } } } catch (IOException e) { e.printStackTrace(); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws Exception { new SocketThreadPoolDemoServer().service(); }}
运行服务端代码后,程序会一直进行监听,直到接收到客户端请求为止。结果如下:
waitting connet…
客户端代码(与单线程完全相同):
public class SocketDemoClient { private String host = "127.0.0.1";// 要发送给服务端的ip private int port = 8000;// 要发送给服务端的端口 private Socket socket; public SocketDemoClient() throws Exception { socket = new Socket(host, port);// 构造Socket客户端,并与连接服务端 } public void talk() throws IOException { try { BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8")); PrintWriter writer = new PrintWriter(socket.getOutputStream()); // 读取本地控制台的消息 BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in)); String msg = null; while ((msg = localReader.readLine()) != null) { writer.println(msg); writer.flush(); System.out.println("send msg:" + reader.readLine()); if ("close".equals(msg)) { break; } } } catch (Exception e) { e.printStackTrace(); } finally { if (socket != null) { socket.close(); } } } public static void main(String[] args) throws Exception { new SocketDemoClient().talk(); }}
由于我们要测试多个客户端连接同一个服务端,所以我们需要多次运行客户端代码。这里我们运行两次之后(称为客户端1、客户端2),查看服务端的Console,会出现以下结果,说明已经连接成功:
waitting connet…
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
我们在去客户端1的Console中输入我们要发送的消息”维护世界和平”,回车确定后,客户端1的Console出现以下结果,消息已经发出:
send msg:维护世界和平
再去客户端2的Console中输入”好好学习天天向上”,回车确定后,客户端2的Console出现以下结果,消息已经发出:
send msg:好好学习天天向上
在服务端的Console中,我们会看到如下结果,说明两个客户端的消息已经被接受:
waitting connet…
new connection accepted:/127.0.0.1:59593
new connection accepted:/127.0.0.1:59596
from /127.0.0.1:59593, receive msg:维护世界和平
from /127.0.0.1:59596, receive msg:好好学习天天向上
- Java千百问_02基本使用(012)_如何编写多线程Socket程序
- Java千百问_02基本使用(011)_如何编写单线程Socket程序
- Java千百问_02基本使用(012)_如何编写非阻塞SocketChannel程序
- Java千百问_02基本使用(001)_如何用记事本编写Java程序
- Java千百问_02基本使用(003)_不使用IDE如何打jar包
- JAVA学习57_ Java千百问_02基本使用(003)_不使用IDE如何打jar包
- Java千百问_02基本使用(006)_eclipse如何保存时格式化
- Java千百问_02基本使用(007)_eclipse变量高亮如何打开
- Java千百问_02基本使用(008)_eclipse如何关闭代码验证
- Java千百问_02基本使用(009)_eclipse如何设置BuildPath
- Java千百问_02基本使用(013)_linux系统如何管理环境变量
- Java千百问_02基本使用(015)_java如何通过汇编方式运行
- Java千百问_02基本使用(014)_mac系统如何管理环境变量
- Java千百问_02基本使用(002)_为什么会报"错误: 找不到或无法加载主类 HelloWord.class"
- Java千百问_08JDK详解(014)_如何编写JVMTI agent程序
- Java千百问_02基本使用(004)_java开发应该使用什么工具
- Java千百问_02基本使用(005)_Mac环境下无法打开eclipse怎么办
- Java千百问_02基本使用(010)_java、javax、sun、org包有什么区别
- Struts2-->布尔值(boolean)类型转换注意问题
- DataBinding框架初体验
- Java回调机制探讨
- java学习:101软件开发工程师(JAVA)初级考试大纲《1》
- Hadoop 调研笔记
- Java千百问_02基本使用(012)_如何编写多线程Socket程序
- 字符串反转
- oracle中的口令文件
- jsp如何获取struts2 action中返回的对象的值
- 多线程下载开源项目xUtils的使用(转载)
- 20. Valid Parentheses
- 如何在MySQL中设置外键约束
- Linux 系统应用编程——网络编程(TCP 协议三次握手过程)
- 敲代码时经常遇到的小细节