标签:
了解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程序
标签:
原文地址:http://blog.csdn.net/ooppookid/article/details/51711323