上篇?Java Socket学习---单线程阻塞?
这次文章中,是在上篇的基础上,在服务端使用了多线程的方式来管理连接,主线程负责接收连接,在接到连接后变创建新的线程,每个线程负责与自己的客户端进行通信。
与单线程阻塞的例子相比来说,服务端可以与多个客户端进行通信了,不过多线程频繁的创建与销毁便会带来很大的资源开销,而系统的网络资源等都是有限的;因此便可以引入线程池,可以在某种程度上重用线程,减少线程的创建和销毁的次数以减少开销。
?
下例代码中包含了使用和不使用线程池(针对Server端)的两种方式,如果测试的时候,解开注释的代码即可以。
?
Server端代码:
class="java">package com.henushang.socket.chapter2; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.henushang.socket.util.SocketUtils; public class EchoServer { private int port = 8000; private ServerSocket serverSocket; private ExecutorService executorService ; // 连接池 private final int POOL_SIZE = 4;// 连接池大小 public EchoServer() throws Exception{ serverSocket = new ServerSocket(port); executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE); System.out.println("waitting connet..."); } /** * 接受连接 * * @author henushang */ 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(); } } } public static void main(String[] args) throws Exception { new EchoServer().service(); } /** * 线程类,负责维持与一个客户端的通信 * * @author henushang */ 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 = SocketUtils.getReader(this.socket); PrintWriter writer = SocketUtils.getWriter(this.socket); String msg = null; while ((msg = reader.readLine()) != null) { System.out.println(msg); // 因为客户端接收消息的时候使用的是readline()方法,如果消息没有以\r\n 结尾的话,客户端则接收不到消息 // writer.write(SocketUtils.echo(msg) + "\r\n"); writer.println(SocketUtils.echo(msg)); writer.flush(); if ("bye".equals(msg)) { break; } } } catch (IOException e) { e.printStackTrace(); } finally{ SocketUtils.close(socket); } } } }
?
Client端代码(与上次代码一样):
package com.henushang.socket; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import com.henushang.socket.util.SocketUtils; public class EchoClient { private String host = "127.0.0.1"; private int port = 8000; private Socket socket ; public EchoClient() throws Exception { socket = new Socket(host, port); } public void talk() throws IOException { try { BufferedReader reader = SocketUtils.getReader(socket); PrintWriter writer = SocketUtils.getWriter(socket); // 读取本地控制台的消息 BufferedReader localReader = new BufferedReader(new InputStreamReader(System.in)); String msg = null; while ((msg = localReader.readLine()) != null) { writer.println(msg); writer.flush(); System.out.println(reader.readLine()); if ("bye".equals(msg)) { break; } } } catch (Exception e) { e.printStackTrace(); }finally { SocketUtils.close(socket); } } public static void main(String[] args) throws Exception{ new EchoClient().talk(); } }
?
SocketUtils代码:
package com.henushang.socket.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.nio.channels.SocketChannel; public class SocketUtils { public static PrintWriter getWriter(Socket socket) throws IOException { OutputStream os = socket.getOutputStream(); return new PrintWriter(os); } public static PrintWriter getWriter(SocketChannel socketChannel) throws IOException { return getWriter(socketChannel.socket()); } public static BufferedReader getReader(Socket socket) throws IOException{ InputStream is = socket.getInputStream(); return new BufferedReader(new InputStreamReader(is, "UTF-8")); } public static BufferedReader getReader(SocketChannel socketChannel) throws IOException{ return getReader(socketChannel.socket()); } public static void close(Socket socket) { try { if (socket != null) { socket.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void close(SocketChannel socketChannel) { try { if (socketChannel != null) { socketChannel.close(); } } catch (Exception e) { e.printStackTrace(); } } public static String echo(String msg) { return "echo:" + msg; } }
?
?