这次文章中,是在上篇的基础上,在服务端使用了多线程的方式来管理连接,主线程负责接收连接,在接到连接后变创建新的线程,每个线程负责与自己的客户端进行通信。
与单线程阻塞的例子相比来说,服务端可以与多个客户端进行通信了,不过多线程频繁的创建与销毁便会带来很大的资源开销,而系统的网络资源等都是有限的;因此便可以引入线程池,可以在某种程度上重用线程,减少线程的创建和销毁的次数以减少开销。
下例代码中包含了使用和不使用线程池(针对Server端)的两种方式,如果测试的时候,解开注释的代码即可以。
Server端代码:
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; } }
相关推荐
NULL 博文链接:https://1358440610-qq-com.iteye.com/blog/2115715
在主线程中通过控制台读取键盘输入时,会产生阻塞。故另外开启一个线程,用于接受客户端的socket消息。服务器在收到一个socket连接之后,把该socket保存到队列中,并对队列中的每个socket开启各自的读写线程。测试...
使用java socket开发的多线程文件上传下载的实例项目,多线程并发测试中可以支持200个,可能由于我电脑的配置问题,一般在并发大于200时client端可能会出现"阻塞"问题,还请大家指教
本项目为我现在负责开发的一个项目,在多线程并发测试中可以支持200个,可能由于我电脑的配置问题,一般在并发大于200时client端可能会出现"阻塞"问题,还请大家指教
DougLee可扩展的网络服务事件驱动Reactor模式基础版多线程版其他变体java.io包中分阻塞IOAPI一览Web服务器,分布式对象系统等等它们的共同特点Read请求解码请求报文业务处理编码响应报文发送响应实际应用中每一个...
* <p>Description: 本实例使用多线程实现多服务功能。 * <p>Copyright: Copyright (c) 2003 * <p>Filename: * @author 杜江 * @version 1.0 */ class moreServer { public static void main (String [] args...
并为每个请求创建新的Socket实例,由于服务端在调用accept()等待客户端的连接请求时会阻塞,直到收到客户端发送的连接请求才会继续往下执行代码,因此要为每个Socket连接开启一个线程。服务器端要同时处理...
jdk供的无阻塞I/O(NIO)有效解决了多线程服务器存在的线程开销问题,但在使用上略显得复杂一些。在NIO中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个CPU...
TCP Socket服务端,支持多个客户端连接,MFC多线程异步收发,防阻塞; 收到客户端报文自动回码确认; 支持服务端向选中客户端发数据,进行测试; 支持记录报文log,可以长时间测试HJ212设备。 支持自己编辑QN=XX~...
1.采用重叠I/O方式实现的socket网络编程,异步非阻塞方式,代码效率比阻塞式的socket编程方式高。2.实现了TCP server方式,只用于服务端,可以支持多客户端。3.可以使用在各种场合用于监控网络数据。4.代码封装成库...
NIO中的特性之一就是零拷贝,在Java中,内存分为堆和栈以及字符串常量值等等,如果有一些数据从IO中读取并且放到堆里面,中间会经过一些缓冲区。 具体来讲,如果要从IO中读取数据,分为两个步骤: (1)从IO流中读取...
它还有一个用于插入您自己的 SocketHandler 类的微型框架。 它使用 Thread-Per-Request 模型和阻塞 I/O(不是网络规模的!!)。 要求 本项目使用构建,因为好多年没写ant构建文件了,有种怀旧的感觉。 测试 在...
基于java tcp socket通信的拆包和装包源码 NettyTree ... 2)多线程模型,有一组NIO线程处理IO操作 有一个专门的NIO线程-Acceptor线程用于监听服务端,接收客户端的TCP连接请求; 有一个NIO线程池,
Java局域网通信——飞鸽传书源代码,大家都知道VB版、VC版还有Delphi版的飞鸽传书软件,但是Java版的确实不多,因此这个Java文件传输实例不可错过,Java网络编程技能的提升很有帮助。 Java聊天程序,包括服务端和...
javathread.zip 10.Java多线程编程(线程池、生产者消费者、存取款实例) javautil.zip 11.Java常用实体类 javaxml.zip 14.XML属性文件 第4部分(6个程序包) javagui.zip 15.Java GUI库对比实例 javaawt.zip ...
� Google 提供了一套 Java 核心包 (J2SE 5,J2SE 6) 的有限子集,尚不承诺遵守 Java 任何 Java 规范 , 可能会造 成J ava 阵营的进一步分裂。 � 现有应用完善度不太够,需要的开发工作量较大。--------------------...
笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此...
javathread.zip 10.Java多线程编程(线程池、生产者消费者、存取款实例) javautil.zip 11.Java常用实体类 javaxml.zip 14.XML属性文件 第4部分(6个程序包) javagui.zip 15.Java GUI库对比实例 javaawt.zip ...