java网络编程精解pdf_Java网络编程精解笔记3:ServerSocket详解

ServerSocket用法详解

1.C/S模式中,Server需要创建特定端口的ServerSocket.->其负责接收client连接请求.

2.线程池->包括一个工作队列和若干工作线程->工作线程不断的从工作队列中取出任务并执行.-->java.util.concurrent->线程池

3.server可利用多线程来处理与多个客户的通信任务.

1.构造ServerSocket

1.重载形式

ServerSocket() throws IOException

ServerSocket(int port) throws IOException

ServerSocket(int port,int backlog) throws IOException

ServerSocket(int port,int backlog,InetAddress bindAddr) throws IOException

port指定服务器要绑定的端口,即服务器要监听的端口;backlog指定客户连接请求队列的长度;bindAddr指定服务器要绑定的IP地址.

2.除了第一个构造方法,其他方法都会与特定端口绑定.

a.如ServerSocket serverSocket = new ServerSocket(80)

如果运行时无法绑定到80端口,则会抛出BindException.原因->

1.端口已经被其他服务器进程占用

2.某些os中,如果没有以超级用户的身份来运行server,则os不允许绑定到1-1023之间的端口

b.port设为0->表示由os来为server分配一个任意可用的端口->匿名端口->

->大部分服务器需要使用明确的端口.->因为client程序需要事先知道server端口,才能方便访问server.

->匿名端口一般适用于server与client之间的临时通信,通信结束则断开连接,且SeverSocket占用的临时端口也被释放.{@link ServerSocket#getLocalPort()}

->如ftp协议->两个并行的TCP连接->控制连接(21端口)和数据连接.

a.TCP client创建一个监听匿名端口的ServerSocket.再把这个ServerSocket监听的端口好发送给TCP服务器.然后TCP服务器主动请求与client连接.此连接用于和服务器建立临时的数据连接.这种方式就是用了匿名端口.

3.设定client连接请求队列的长度

1.server运行时,可能会同时监听到多个client的连接请求.

2.管理client连接请求的任务是由os来完成的.os将这些连接请求存储在一个先进先出队列中.

3.许多os限定了队列的最大长度.一般为50.

4.当队列中的连接请求达到了队列的最大容量时,server进程所在的主机会拒绝新的连接请求.->只有当server进行通过ServerSocket#accept从队列中取出连接请求->队列腾出空位->队列才能继续加入新的连接请求.

5.对于client来说,如果其连接请求被加入的server的连接队列中,就意味着client与server连接建立成功->client进程从Socket的构造方法中返回

->如果client进程发出的连接请求被server拒绝,则Socket构造方法抛出ConnectionException.

6.ServerSocket构造中的backlog参数用来显示的设置连接请求队列的长度,其将覆盖os限定的队列的最大长度.->注意依然采用os限定的队列的长度的情况:

1.backlog参数的值大于os限定的队列的最大长度.

2.backlog参数的值小于或等于0

3.其构造方法中未设置backlog参数.

4.设定绑定的ip地址

1.如果主机只有一个ip地址,默认情况下,server程序与其绑定.

2.ServerSocket构造方法可显示的指定服务器要绑定的ip地址,该构造方法适用于具有多个ip地址的主机.如一个主机具有两个网卡.一个用于连接Internet,以一个用于连接本地局域网.如果server仅仅被本地局域网访问则可显示指定绑定的ip地址.

5.默认构造方法的作用

1.ServerSocket有一个不带参数的构造方法->其创建的ServerSocket不与任何端口绑定->需调用bind与特定端口绑定.

2.其用于在于允许server在绑定到特定端口之前,可先设置SerevrSocket的一些选项->因为一旦与特定端口绑定,有些选项就不能再用.

如:

ServerSocket serverSocket = new ServerSocket();

serverSocket.setReuseAddress(true);//先设置serverSocket的选项,该选项必须在bind之前才有效

serverSocket.bind(new InetAddress(8000));//再执行绑定端口

2.接收和关闭与客户的连接

1.ServerSocket#accept->从连接请求队列中取出一个client的连接请求->创建于client连接的Socket对象,返回->

2.如果队列中没有连接请求,accept方法则会一直等待,知道接收了连接请求才返回

3.->server从Socket对象获得输入输出流->与client交换数据->当server正在进行发送数据的操作时->client断了连接->server抛出IOException的子类SocketException:

java.net.SocektException:Connection reset by peer.

->这只是server与单个client通信中的异常,这种异常应该被捕获,使得server能继续与其他client通信.

4.->单线程server采用的通信流程:

public void service()

{

while(true)

{

Socket socket = null;

try

{

socket = serverSocket.accept();//从连接队列中取出一个连接

//接收和发送数据

...

}

catch(IOException e)

{

//这只是与单个client通信时遇到的异常,可能是由于client过早断开连接引起的

//该异常不应该中断整个while循环

e.printStackTrace();

}

finally//不管与client是通信正常结束还是异常结束,最后都关闭socket,断开与client的连接

{

try

{

if(socket != null)

{

socket.close();//与一个client通信结束后,要关闭socket

}

}

catch(IOException e)

{

e.printStackTrace();

}

}

}

}

3.关闭ServerSocket:

1.ServerSocket#close->使得server释放占用的端口->断开与所有client的连接.

2.当一个server程序运行结束时,即使没有执行close方法,os也会释放这个server占用的端口->server并不一定要在结束之前执行其close方法.

3.某些情况,如果希望及时释放server端口,以便其他程序占用端口,则可显示调用ServerSocket#close方法.

4.ServerSocket#isClosed判断ServerSocket是否关闭->只有执行了ServerSocket#close后,其才返回true.->即使ServerSocket还未与特定端口绑定,isClosed亦返回false.

5.isBound判断ServerSocket是否已经与一个端口绑定.->只要ServerSocket与一个端口绑定,即使已关闭->isBound也返回true.

6.判断一个ServerSocket是否已经与一个特定端口绑定且还没有被关闭:

boolean isOpen = serverSocket.isBound() && !serverSocket.isClosed()

4.获取ServerSocket的信息

1.public InetAddress getInetAddress()//获得server绑定的ip地址

2.public intgetLocalPort()//获得server绑定的端口

->端口设为0,os为server分配一个匿名端口

3.FTP:

1.ftp使用两个并行的tcp连接,一个是控制连接,一个是数据连接.

2.控制连接用于在client和server之间发送控制信息,如用户名和口令,改变远程目录的命令或上传和下载的命令.

3.数据连接用于传送文件.

4.tcp server在21端口监听控制连接.

5.数据连接的建立两种方式:

1.tcp server在20端口上监听数据连接,tcp client主动请求建立与该端口的连接

2.匿名端口:tcp client->创建匿名端口的ServerSocket->#getLocalPort发送到server.->tcp server主动请求建立与client的连接.

->client使用匿名端口,用于和server建立临时的数据连接

->实际应用中,server也可使用匿名端口.

5.ServerSocket选项

1.SO_TIMEOUT:表示等待client连接的超时时间.

1.public void setSoTimeout(int timeout) throws SocketException

2.public int getSoTimeout() throws IOException

3.该选项表示ServerSocket的accept方法的等待client连接的超时时间.->ms

4.选项为0,表示永远不会超时,也是其默认值.

5.ServerSocket#accept->如果连接请求队列为空,server就会一直等待->直到收到了client连接才从accept返回->设定了超时时间,如果等待时间超过了超时时间,则抛出SocketTimeoutException.->InterruptedException的子类.

6.Server执行serverSocket#accept方法时,等待client连接的过程称之为阻塞.

2.SO_REUSEADDR:表示是否允许重用服务器所绑定的地址.

1.public void setReuseAddress(boolean on) throws SocketException

2.public boolean getReuseAddress() throws SocketException

3.同Socket#SO_REUSEADDR->决定如果网络上仍有数据向旧的ServerSocket传输数据,是否允许新的ServerSocket绑定到旧的ServerSocket同样的端口上.该选项的默认值与os有关,有的os允许重用端口,有的os不允许重用.

4.ServerSocket关闭时,如果网络上还有发送到这个ServerSocket的数据,这个ServerSocket不会立刻释放本地端口,而是会等待一段时间,确保接收到了网络发过来的延迟数据,然后再释放端口.

5.许多server程序使用固定端口。Server程序关闭后->有可能其端口还被占用一段时间->如果此时在同一个主机上重启server程序->由于端口被占用,使得server程序无法绑定到该端口->server启动失败,抛出BindException.

Exception in thread "main" java.net.BindException:Address already in use:JVM_Bind.

6.为确保一个进程关闭ServerSocket后,即使os还未释放端口,同一个主机的上其他进程可以立刻重用该端口->ServerSocket#serReuseAddress(true)

if(!serverSocket.getReuseAddress()){serverSocket.setReuseAddress(true)}

7.必须在serverSocket还未绑定到一个本地端口前调用.否则无效.->两个公用一个端口端口的进程必须都调用setReuseAddress(true)->一个进程关闭ServerSocket后,另一个进程可立即重用相同端口

3.SO_REVBUF:表示接收数据的缓冲区的大小.

1.public void setReceiveBufferSize(int size) throws SocketException

2.public int getReceiveBufferSize() throws SocketException

3.该选项表示Server用于接收数据的缓冲区的大小,字节为单位.(传输大的连续的数据块,http/ftp可以使用较大的缓冲区,减少传输数据的次数,提高传输数据的效率;对于交互频繁且单次数据量较小的通信 telnet和网络游戏,则应该采用较小的缓冲区,确保及时把小批量的数据发送给对方)

4.该默认值与os有关.->如果要设置超过64kb的缓冲区必须在serverSocket绑定到特定端口前设置才有效.

5.执行ServerSocket#setReceiveBufferSize->相当于对所有由serverSocket#accept返回的Socket设置接收数据的缓冲区的大小.

4.public void setPerformancePreferences(int connectionTime,int latency,int bandwidth)->同Socket#setPerformancePreferences->用于设定连接时间,延迟和带宽的相对重要性.

6.创建多线程的服务器

1.chap1#EchoServer有一个很大的问题就是无法同时与多个client通信.->

1.当前这个EchoServer的问题是只能连接一个Client,只有当前的client输入bye,结束连接的时候,才会处理下一个client

2.原因在于service方法,while(br.readLine() != null),这里,当Client没有输入数据时,线程则挂起,阻塞,等待client输入

->如果同时又多个client请求.这些client则必须排队等待.

2.许多实际应用要求server具有同时为多个client提供服务器的能力-如http服务器.

3.衡量server具有同时响应多个客户的能力-并发性能

1.能同时接收并处理多个client连接

2.对于每个client,都会迅速给与响应

4.用多个线程来同时为多个client提供服务,这是提高server的并发性能的最常用的手段.

5.

a.为每个客户分配一个工作线程.伪代码:

public void service()

{

while(true)

{

ServerSocket socket = null;

try

{

socket = serverSocket.accept();//接收client连接

//EchoHandler实现了Runnable接口,其run负责与单个client通信.通信结束则断开连接.工作线程也会自然终止.

Thread workThread = new Thread(new EchoHandler(socket));//创建一个工作线程

workThread.start();//启动工作线程

}

catch(IOException e)

{

e.printStackTrace();

}

}

}

b.该实现缺点:

1.server创建和销毁工作线程的开销,包括所花费的时间和系统资源很大.->如果server与多client通信并且每个client的通信时间都很短->那么server为client创建新线程的开销比实际与client通信的开销还要大.

2.除了创建和销毁线程的开销,活动的线程也消耗系统资源.每个线程本身会占用一定的内存,每个线程约1M.如果有大量client连接server,就必须创建爱你大量工作线程->消耗了大量内存,导致系统的内存空间不足.(-Xss,设置每个线程的堆栈大小)

3.如果线程数目固定,并且每个线程都有很长的生命周期,则线程切换也是相对固定的.->不同的os有不同的切换周期,一般在20ms.这里所说的线程切换是在Java虚拟机以及底层os的调度之下,线程之间转让cpu的使用权.如果频繁创建和销毁线程,则导致频繁切换线程;因为一个线程被销毁后,必须要把cpu转让给另一个已就绪的线程,使该线程或的运行机会.这种情况下,线程之前的切换不再遵循系统的固定切换周期,切换线程的开销甚至比创建及销毁线程的开销还要大.

->引入线程池.

6.线程池为线程生命周期开销问题和系统资源不足问题提供了解决方案:

1.线程池预先创建一些工作线程->其不断的从工作队列中取出任务->执行任务->工作线程执行完一个任务->继续执行工作队列的下一个任务->

2.线程池减少了创建和销毁的次数,每个工作线程都可以被一直重用,能执行多个任务

3.可根据系统的负载能力,方便的调整线程池中线程的数目->防止因为消耗过量系统资源而导致系统崩溃.

c.使用java.util.concurrent包提供了现成的线程池的实现.->比ThreadPoolImpl的要健壮而且功能更强大.

1.public interfaceExecutor#void execute(Runnable command)

2.public interfaceExecutorServiceextends Executor

1.voidshutdown()

2.ListshutdownNow()

3.booleanawaitTermination(long timeout, TimeUnit unit) throws InterruptedException

4. Future submit(Callable task)

5. Futuresubmit(Runnable task, T result)

6.Future>submit(Runnable task)

7. List>invokeAll(Collection extends Callable> tasks) throws InterruptedException

8. TinvokeAny(Collection extends Callable> tasks) throws InterruptedException, ExecutionException

9.booleanisTerminated()

3.public classExecutors

-> Factory and utility methods

1.    public static ExecutorServicenewCachedThreadPool() {

return newThreadPoolExecutor(0, Integer.MAX_VALUE,

60L, TimeUnit.SECONDS,

new SynchronousQueue());}

2.public static ExecutorServicenewFixedThreadPool(int nThreads) {

return new ThreadPoolExecutor(nThreads, nThreads,

0L, TimeUnit.MILLISECONDS,

new LinkedBlockingQueue());}

3. public static ExecutorServicenewSingleThreadExecutor() {

return newFinalizableDelegatedExecutorService

(newThreadPoolExecutor(1, 1,

0L, TimeUnit.MILLISECONDS,

new LinkedBlockingQueue()));}

->Note however that if this single thread terminates due to a failure during execution prior to shutdown, a new one will take its place if needed to execute subsequent tasks.

->与newFixedThreadPool(1)区别->Unlike the otherwise equivalent newFixedThreadPool(1) the returned executor is guaranteed not to be reconfigurable to use additional threads.

->The difference is (only) that the SingleThreadExecutor cannot have its thread size adjusted later on, which you can do with a FixedThreadExecutor by calling ThreadPoolExecutor#setCorePoolSize (needs a cast first).->((ThreadPoolExecutor)newFixedThreadPool(1)).setCorePoolSize(3)->

->ThreadPoolExecutor->

protected void finalize() { shutdown();}->因为DelegatedExecutorService持有了ThreadPoolExecutor引用->所以FinalizableDelegatedExecutorService->

->static class FinalizableDelegatedExecutorService extends DelegatedExecutorService->#finalize->super.shutdown->即在执行finalize的时候调用shutdown->因为其持有ExecutorService引用,所以其不能finalize->只能持有者调用finalize->

4.   publicThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime,TimeUnit unit,BlockingQueue workQueue) {

this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);}

4.public abstract classAbstractExecutorServiceimplements ExecutorService

5.public interfaceScheduledExecutorServiceextends ExecutorService

6.public classThreadPoolExecutorextends AbstractExecutorService

7.public classScheduledThreadPoolExecutorextends ThreadPoolExecutor implements ScheduledExecutorService

7.使用线程池的注意事项:

1.死锁

1.A线程持有对象X的锁并等待对象Y的锁->B线程持有对象Y的锁并等待对象X的锁->A,B线程都不释放自己持有的锁->并且等待对方的锁->导致两个线程永远等待下去->产生死锁

2.线程池死锁->所有工作线程都在执行各自任务时被阻塞->等待某个任务A的执行结果->而任务A仍在工作队列中->没有空闲线程->A一直不能被执行->是的线程池的所有工作线程都永远阻塞->死锁->

2.系统资源不足

线程池线程数目多->消耗内存和其他系统资源.->影响系统性能.

3.并发错误

ThreadPoolImpl的工作队列依靠wait和notify使工作线程即使取得任务.->如果编码不正确,可能会丢失通知->导致工作线程一直保持空闲状态->无视工作队列需要处理的任务->使用这些方法必须格外小心->最好使用现有的,比较成熟的线程池->如concurrent包中的线程池类.

4.线程泄露

1.对于工作线程数目固定的线程池->如果工作线程在执行任务抛出RuntimeException或Error->并且这些异常或错误没有被捕获->工作线程就会异常终止->线程池失去了一个工作线程->如果所有的工作线程都异常终止->线程池就为空->

2.工作线程在执行一个任务被阻塞->如等待用户输入数据->但由于用户一直不输入数据->导致工作线程一直被阻塞->这样的工作线程名存实亡->不执行任何任务了->如果线程池中所有工作线程都处于这样的阻塞状态->线程池无法处理新加入的任务

5.任务过载

当工作队列中有大量排队等待执行的任务时->这些任务本身可能消耗太多系统资源而引起系统资源缺乏.

8.使用线程池遵循原则:

1.如果任务A在执行过程中需要同步等待任务B的执行结果->任务A不适合加入到线程池的工作队列->如果把像任务A一样的需要等待其他任务执行结果的任务加入到工作队列中->可能会导致线程池的死锁.

2.如果执行某个任务可能会阻塞并且会长时间阻塞->应该设定超时时间->避免工作线程永久的阻塞下去->导致线程泄露->

->服务器程序中->线程等待client连接 或者 等待client发送的数据时都可能会阻塞->

1.ServerSocket#setSoTimeout(int timeout)->设定等待client连接的超时时间

2.对于每个与client连接的Socket->Socket#setSoTimeout(int timeout)->设定等待client发送数据的超时时间.

3.了解任务的特点:

1.分析任务时经常会执行阻塞的io操作->还是执行一直不会阻塞的运算操作->前者时断时续的占用cpu,而后者对cpu具有更高的利用率->预计完成人呢无的大概时间->是短时间任务还是长时间任务?->根据任务的特点->对任务进行分类->不同类型的任务加入到不同线程池的工作队列中->根据任务的特点->分别调整每个线程池.

4.调整线程池的大小:

1.线程池的最佳大小主要取决于系统的可用cpu的数目以及工作队列中任务的特点.

2.如一个具有n个cpu的os上只有一个工作队列且其中全部是运算性质的任务,即不会阻塞的任务,则线程中具有n或n+1个工作线程时,一般会获得最大的cpu利用率。

3.如果工作队列中包含会执行I/O操作并常常阻塞的任务,则要让线程池的大小超过可用cpu的数目,因为并不是所有工作线程都一直在工作。选择一个典型的任 务,然后估计在执行这个任务的过程中,等待时间(WT)与实际占用CPU进行运算的时间(ST)之间的比例WT/ST。对于一个具有N个CPU的系统,需 要设置大约N×(1+WT/ST)个线程来保证CPU得到充分利用。注-(n + 平均阻塞的线程)

4.CPU利用率不是调整线程池大小过程中唯一要考虑的事项。随着线程池中工作线程数目的增长,还会碰到内存或者其他系统资源的限制,如套接字、打开的文件句柄或数据库连接数目等。要保证多线程消耗的系统资源在系统的承载范围之内

5.避免任务过载。服务器应根据系统的承载能力,限制客户并发连接的数目。当客户并发连接的数目超过了限制值,服务器可以拒绝连接请求,并友好地告知客户:服务器正忙,请稍后再试.

9.关闭服务器

1.之前的EchoServer都无法关闭自身->只能靠os强制终止->处理方式虽然简单,但是会导致服务器正在执行的任务被突然中断->server处理的任务重要->不允许被突然中断->server需在恰当的时刻关闭自己.

注:1.很多游戏服务器程序采用ShutdownHooker来进行jvm进程退出的清理工作,如linux下kill的时候会调用钩子.

2.本人倾向于在游戏服务器正常的关闭自己->理想的情况下是向游戏服务器发送shutdown命令,然后游戏服务器执行清理工作,所有线程执行shutdown->jvm进程自然退出.

部分源码:

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *测试server的连接请求队列特性的client,client试图100次与server建立连接

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png第 1 次连接成功

d18c02628675d0a2c816449d98bda930.png第 2 次连接成功

d18c02628675d0a2c816449d98bda930.png第 3 次连接成功

d18c02628675d0a2c816449d98bda930.pngException in thread "main" java.net.ConnectException: Connection refused: connect

d18c02628675d0a2c816449d98bda930.png    at java.net.PlainSocketImpl.socketConnect(Native Method)

d18c02628675d0a2c816449d98bda930.png    at java.net.PlainSocketImpl.doConnect(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.PlainSocketImpl.connectToAddress(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.PlainSocketImpl.connect(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.SocksSocketImpl.connect(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.Socket.connect(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.Socket.connect(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.Socket.(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.Socket.(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at com.game.landon.serverSocket.Client.main(Client.java:27)

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png第 1 次连接成功

d18c02628675d0a2c816449d98bda930.png第 2 次连接成功

d18c02628675d0a2c816449d98bda930.png第 3 次连接成功

d18c02628675d0a2c816449d98bda930.png第 4 次连接成功

d18c02628675d0a2c816449d98bda930.png第 5 次连接成功

d18c02628675d0a2c816449d98bda930.png

9b8a8a44dd1c74ae49c20a7cd451974e.png

d18c02628675d0a2c816449d98bda930.png第 100 次连接成功

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-2

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassClient

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngfinalintlength=100;

d18c02628675d0a2c816449d98bda930.png        String host="localhost";

d18c02628675d0a2c816449d98bda930.pngintport=8000;

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        Socket[] sockets=newSocket[length];

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.pngfor(inti=0;i

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            sockets[i]=newSocket(host,port);

d18c02628675d0a2c816449d98bda930.png            System.out.println(String.format("第 %d 次连接成功", i+1));

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        Thread.sleep(3*1000);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.pngfor(inti=0;i

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            sockets[i].close();//断开连接ecedf933ec37d714bd4c2545da43add2.png}ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.BufferedReader;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.InputStream;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.InputStreamReader;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.OutputStream;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.PrintWriter;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *Echo Handler.负责与client通信

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-11

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassEchoHandlerimplementsRunnable

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateSocket socket;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicEchoHandler(Socket socket)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthis.socket=socket;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * echo to client

d18c02628675d0a2c816449d98bda930.png     *@parammsg

d18c02628675d0a2c816449d98bda930.png     *@returnecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicString echo(String msg)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn"echo:"+msg;

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * Wrapped {@linkSocket#getOutputStream()} to PrintWriter

d18c02628675d0a2c816449d98bda930.png     *@paramsocket

d18c02628675d0a2c816449d98bda930.png     *@returnd18c02628675d0a2c816449d98bda930.png     *@throwsIOException

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngprivatePrintWriter getWriter(Socket socket)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//返回输出流对象,向输出流写数据,就能向对方发送数据d18c02628675d0a2c816449d98bda930.pngOutputStream socketOut=socket.getOutputStream();

d18c02628675d0a2c816449d98bda930.png//public PrintWriter(OutputStream out, boolean autoFlush)d18c02628675d0a2c816449d98bda930.pngreturnnewPrintWriter(socketOut,true);

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * Wrapped {@linkSocket#getInputStream()} to BufferedReader

d18c02628675d0a2c816449d98bda930.png     *@paramsocket

d18c02628675d0a2c816449d98bda930.png     *@returnd18c02628675d0a2c816449d98bda930.png     *@throwsIOException

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngprivateBufferedReader getReader(Socket socket)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//返回输入流对象;只需从输入流读数据,就能接收来自对方的数据d18c02628675d0a2c816449d98bda930.pngInputStream socketIn=socket.getInputStream();

d18c02628675d0a2c816449d98bda930.pngreturnnewBufferedReader(newInputStreamReader(socketIn));

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.png    @Override

d18c02628675d0a2c816449d98bda930.pngpublicvoidrun()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            System.out.println("New Connection accepted:"+socket.getInetAddress()+":"+socket.getPort());

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png            BufferedReader br=getReader(socket);

d18c02628675d0a2c816449d98bda930.png            PrintWriter pw=getWriter(socket);

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png            String msg=null;

d18c02628675d0a2c816449d98bda930.png//read from clientd18c02628675d0a2c816449d98bda930.pngwhile((msg=br.readLine())!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                System.out.println(msg);

d18c02628675d0a2c816449d98bda930.png//write to clientd18c02628675d0a2c816449d98bda930.pngpw.println(echo(msg));

d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.pngif(msg.equals("bye"))

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngbreak;

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pngfinally97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngif(socket!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//close socketd18c02628675d0a2c816449d98bda930.pngsocket.close();

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.ExecutorService;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.Executors;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *用JDK自带的Executor线程池实现的EchoServer.

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-22

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassEchoServerExecutors

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateintport=8000;

d18c02628675d0a2c816449d98bda930.pngprivateServerSocket serverSocket;

d18c02628675d0a2c816449d98bda930.pngprivateExecutorService executorService;

d18c02628675d0a2c816449d98bda930.pngprivatefinalintPOOL_SIZE=4;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicEchoServerExecutors()throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        serverSocket=newServerSocket(port);

d18c02628675d0a2c816449d98bda930.png        executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        System.out.println("EchoServerExecutors launched

9b8a8a44dd1c74ae49c20a7cd451974e.png");

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicvoidservice()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(true)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            Socket socket;

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                socket=serverSocket.accept();

d18c02628675d0a2c816449d98bda930.png                executorService.execute(newEchoHandler(socket));

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngnewEchoServerExecutors().service();

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *每client每thread实现的Echo Server,用{@linkcom.game.landon.entrance.EchoClient}测试即可

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-11

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassEchoServerPerClientPerThread

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateintport=8000;

d18c02628675d0a2c816449d98bda930.pngprivateServerSocket serverSocket;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicEchoServerPerClientPerThread()throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        serverSocket=newServerSocket(port);

d18c02628675d0a2c816449d98bda930.png        System.out.println("EchoServerPerClientPerThread launched

9b8a8a44dd1c74ae49c20a7cd451974e.png");

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * echo server主业务循环

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicvoidservice()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(true)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            Socket socket=null;

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                socket=serverSocket.accept();

d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.png//EchoHandler实现了Runnable接口,其run负责与单个client通信.通信结束则断开连接.工作线程也会自然终止.d18c02628675d0a2c816449d98bda930.pngThread workThread=newThread(newEchoHandler(socket));

d18c02628675d0a2c816449d98bda930.png                workThread.start();

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String

9b8a8a44dd1c74ae49c20a7cd451974e.pngargs)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        EchoServerPerClientPerThread server=newEchoServerPerClientPerThread();

d18c02628675d0a2c816449d98bda930.png        server.service();

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *用{@linkThreadPoolImpl}实现的EchoServer,可提供优雅的关闭方法->关闭ServerSocket/关闭线程池

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-17

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassEchoServerThreadPool

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateintport=8000;

d18c02628675d0a2c816449d98bda930.pngprivateServerSocket serverSocket;

d18c02628675d0a2c816449d98bda930.pngprivateThreadPoolImpl threadPool;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngprivatefinalintPOOL_SIZE=4;//单cpu时线程池的工作线程的数目d18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.pngpublicEchoServerThreadPool()throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        serverSocket=newServerSocket(port);

d18c02628675d0a2c816449d98bda930.png//根据当前os可用的cpu数目设定线程池中的线程数目d18c02628675d0a2c816449d98bda930.pngthreadPool=newThreadPoolImpl(Runtime.getRuntime().availableProcessors()*POOL_SIZE);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        System.out.println("EchoServerThreadPool started.");

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicvoidservice()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(true)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            Socket socket;

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                socket=serverSocket.accept();

d18c02628675d0a2c816449d98bda930.png                threadPool.execute(newEchoHandler(socket));//将与client echo的任务提交给线程池ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngnewEchoServerThreadPool().service();

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.BufferedReader;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.InputStreamReader;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.SocketException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.SocketTimeoutException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.ExecutorService;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.Executors;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.RejectedExecutionException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.TimeUnit;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *可关闭自身的EchoServer

d18c02628675d0a2c816449d98bda930.png *

 
 

d18c02628675d0a2c816449d98bda930.png *目前有一个问题是如果启动了EchoServer,然后启动了EchoClient->再启动ShutdownClient->如果EchoClient一直不输入数据->

d18c02628675d0a2c816449d98bda930.png *即使EchoServer已经shutdown->EchoClient进程也一直没停止->因为EchoClient#talk->是一直在等待client输入->EchoServer shutdown后->输入任意

d18c02628675d0a2c816449d98bda930.png *->会抛出java.net.SocketException: Software caused connection abort: recv failed

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-23

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassEchoServerWithShutdown

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateintport=8000;

d18c02628675d0a2c816449d98bda930.pngprivateServerSocket serverSocket;

d18c02628675d0a2c816449d98bda930.pngprivateExecutorService executorService;

d18c02628675d0a2c816449d98bda930.pngprivatefinalintPOOL_SIZE=4;

d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**监听shutdown的port*/d18c02628675d0a2c816449d98bda930.pngprivateintportForShutdown=8001;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**监听shutdown的ServerSocket*/d18c02628675d0a2c816449d98bda930.pngprivateServerSocket serverSocketForShutdown;

d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**server是否shutdown*/d18c02628675d0a2c816449d98bda930.pngprivatebooleanisShutdown=false;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicEchoServerWithShutdown()throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        serverSocket=newServerSocket(port);

d18c02628675d0a2c816449d98bda930.png        serverSocket.setSoTimeout(60*1000);//设定等待client连接的超时时间为60秒d18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.png        serverSocketForShutdown=newServerSocket(portForShutdown);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        executorService=Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_SIZE);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//启动shutdown线程d18c02628675d0a2c816449d98bda930.pngshutdownThread.start();

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        System.out.println("EchoServerWithShutdown launched

9b8a8a44dd1c74ae49c20a7cd451974e.png");

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicvoidservice()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(!isShutdown)//主循环.shutdown线程执行shutdown后,下次循环的时候就会退出service方法97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            Socket socket=null;

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                socket=serverSocket.accept();

d18c02628675d0a2c816449d98bda930.png//设置等待client发送数据的超时时间为60秒->如果client60秒内未发送数据->则EchoHandler#79L->抛出java.net.SocketTimeoutException: Read timed out

d18c02628675d0a2c816449d98bda930.png//->EchoHandler这个task自然结束->线程池自然结束d18c02628675d0a2c816449d98bda930.pngsocket.setSoTimeout(60*1000);

d18c02628675d0a2c816449d98bda930.png//可能会抛出RejectedExecutionException->shutdown线程调用了executorService#shutdownd18c02628675d0a2c816449d98bda930.pngexecutorService.submit(newEchoHandler(socket));

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(SocketTimeoutException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(RejectedExecutionException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngif(socket!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                        socket.close();

ecedf933ec37d714bd4c2545da43add2.png                    }ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.pngcatch(IOException ie)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.pngreturn;//退出serviceecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(SocketException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

d18c02628675d0a2c816449d98bda930.png//serverSocket.accept()->serverSocket被shutdown线程关闭d18c02628675d0a2c816449d98bda930.pngif(e.getMessage().indexOf("socket closed")!=-1)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn;//退出serviceecedf933ec37d714bd4c2545da43add2.png}ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**执行关闭server的shutdown线程*/d18c02628675d0a2c816449d98bda930.pngprivateThread shutdownThread=newThread()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicvoidstart()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//设置为后台线程(守护线程),用户线程全部关闭后,jvm自动退出d18c02628675d0a2c816449d98bda930.pngsetDaemon(true);

d18c02628675d0a2c816449d98bda930.pngsuper.start();

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.pngpublicvoidrun()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(!isShutdown)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                Socket socketForShutdown=null;

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    socketForShutdown=serverSocketForShutdown.accept();

d18c02628675d0a2c816449d98bda930.png                    BufferedReader br=newBufferedReader(newInputStreamReader(socketForShutdown.getInputStream()));

d18c02628675d0a2c816449d98bda930.png                   

d18c02628675d0a2c816449d98bda930.png                    String cmd=br.readLine();

d18c02628675d0a2c816449d98bda930.png                   

d18c02628675d0a2c816449d98bda930.pngif(cmd.equals("shutdown"))

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//server执行关闭开始时间d18c02628675d0a2c816449d98bda930.pnglongbeginTime=System.currentTimeMillis();

d18c02628675d0a2c816449d98bda930.png                       

d18c02628675d0a2c816449d98bda930.png                        socketForShutdown.getOutputStream().write("server is shutdowning

9b8a8a44dd1c74ae49c20a7cd451974e.png\r\n".getBytes());

d18c02628675d0a2c816449d98bda930.png                       

d18c02628675d0a2c816449d98bda930.png//设置关闭状态d18c02628675d0a2c816449d98bda930.pngisShutdown=true;

d18c02628675d0a2c816449d98bda930.png                       

d18c02628675d0a2c816449d98bda930.png//请求关闭线程池->线程池不再接收新的任务->但是会执行完工作队列现有的任务d18c02628675d0a2c816449d98bda930.pngexecutorService.shutdown();

d18c02628675d0a2c816449d98bda930.png                       

d18c02628675d0a2c816449d98bda930.png//等待关闭线程池,每次等待的超时时间为30秒(shutdown线程blocked.)d18c02628675d0a2c816449d98bda930.pngwhile(!executorService.isTerminated())

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                            executorService.awaitTermination(30, TimeUnit.SECONDS);

ecedf933ec37d714bd4c2545da43add2.png                        }d18c02628675d0a2c816449d98bda930.png                       

d18c02628675d0a2c816449d98bda930.png//线程池terminate后d18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.png                        serverSocket.close();//关闭ServerSocketd18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.pnglongendTime=System.currentTimeMillis();

d18c02628675d0a2c816449d98bda930.png                        socketForShutdown.getOutputStream().write(("echo server has shutdown..used:"+(endTime-beginTime)+"milliseconds\r\n").getBytes());

d18c02628675d0a2c816449d98bda930.png                       

d18c02628675d0a2c816449d98bda930.png                        socketForShutdown.close();

d18c02628675d0a2c816449d98bda930.png                        serverSocketForShutdown.close();

ecedf933ec37d714bd4c2545da43add2.png                    }d18c02628675d0a2c816449d98bda930.pngelse97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                        socketForShutdown.getOutputStream().write("err cmd".getBytes());

d18c02628675d0a2c816449d98bda930.png                        socketForShutdown.close();

ecedf933ec37d714bd4c2545da43add2.png                    }ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.pngcatch(Exception e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    };

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngnewEchoServerWithShutdown().service();

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *测试ServerSocket匿名端口

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-5

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassRandomPort

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String

9b8a8a44dd1c74ae49c20a7cd451974e.pngargs)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//port 设为0,表示匿名端口d18c02628675d0a2c816449d98bda930.pngServerSocket serverSocket=newServerSocket(0);

d18c02628675d0a2c816449d98bda930.png        System.out.println(serverSocket.getInetAddress()+":"+serverSocket.getLocalPort());

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *测试server的连接请求队列特性的server

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-2

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassServer

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngprivateintport=8000;

d18c02628675d0a2c816449d98bda930.pngprivateServerSocket serverSocket;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicServer()throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        serverSocket=newServerSocket(port,3);//设置连接请求队列的长度为3d18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.png        System.out.println("server started");

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.png//只要该方法执行,不断执行accept方法->从队列中取出连接请求->便可以使队列及时腾出空位以容纳新的连接请求d18c02628675d0a2c816449d98bda930.pngpublicvoidservice()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(true)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            Socket socket=null;

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                socket=serverSocket.accept();//从连接队列中取出一个连接d18c02628675d0a2c816449d98bda930.pngSystem.out.println("New Connection accepted:"+socket.getInetAddress()+":"+socket.getPort());//打印连接进来的socket ip:端口ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngfinally97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngif(socket!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                        socket.close();

ecedf933ec37d714bd4c2545da43add2.png                    }ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        Server server=newServer();

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//TimeUnit.MILLISECONDS.sleep(10 * 60 * 1000);//睡眠10分钟d18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.png        server.service();

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.BufferedReader;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.InputStreamReader;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *向EchoServer发送shutdown的client

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-23

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassShutdownEchoClient

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        Socket socket=null;

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            socket=newSocket("localhost",8001);

d18c02628675d0a2c816449d98bda930.png//必须发送一行数据.因为handler调用的是br.readLined18c02628675d0a2c816449d98bda930.pngsocket.getOutputStream().write("shutdown\r\n".getBytes());

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png//接收server反馈d18c02628675d0a2c816449d98bda930.pngBufferedReader br=newBufferedReader(newInputStreamReader(socket.getInputStream()));

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png            String msg=null;

d18c02628675d0a2c816449d98bda930.pngwhile((msg=br.readLine())!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                System.out.println(msg);

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.pngfinally97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngif(socket!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    socket.close();

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *ServerSocket#close

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-3

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassTestServerSocketClose

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngfor(intport=1;port<=65535;port++)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                ServerSocket serverSocket=newServerSocket(port);

d18c02628675d0a2c816449d98bda930.png                serverSocket.close();//马上关闭,及时释放它占用的端口,避免临时占用系统的大多数端口ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(IOException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                System.err.println(String.format("[%d] is occupied by other server process", port));

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.InetSocketAddress;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *测试ServerSocket#SO_RCVBUF选项

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-9

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassTestServerSocketRcvBuf

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        ServerSocket serverSocket=newServerSocket(8000);

d18c02628675d0a2c816449d98bda930.pngintrecBufSize=serverSocket.getReceiveBufferSize();

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//输出:Windows 7:8192d18c02628675d0a2c816449d98bda930.pngSystem.out.println(System.getProperties().getProperty("os.name")+":"+recBufSize);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        ServerSocket ss2=newServerSocket();

d18c02628675d0a2c816449d98bda930.png//如果设置要超过64k以上的缓冲区,则必须bind之前调用    .暂时未确认.d18c02628675d0a2c816449d98bda930.pngss2.setReceiveBufferSize(65*1024*1024);

d18c02628675d0a2c816449d98bda930.png        ss2.bind(newInetSocketAddress(8001));

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.LinkedList;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *线程池的一个简单实现

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-11

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png//A thread group represents a set of threads. In addition, a threadgroup can also include other thread groups4f1150b881333f12a311ae9ef34da474.pngpublicclassThreadPoolImplextendsThreadGroup

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**工作队列*/d18c02628675d0a2c816449d98bda930.pngprivateLinkedListworkQueue;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**线程池是否关闭*/d18c02628675d0a2c816449d98bda930.pngprivatebooleanisClosed;

d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**线程池id*/d18c02628675d0a2c816449d98bda930.pngprivatestaticintthreadPoolID;

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**线程id*/d18c02628675d0a2c816449d98bda930.pngprivateintthreadID;

d18c02628675d0a2c816449d98bda930.png   

d18c02628675d0a2c816449d98bda930.pngpublicThreadPoolImpl(intpoolSize)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngsuper("ThreadPool-"+(threadPoolID++));

d18c02628675d0a2c816449d98bda930.png//1.Changes the daemon status of this thread group

d18c02628675d0a2c816449d98bda930.png//2.A daemon thread group is automatically destroyed when its last thread is stopped or its last thread group is destroyedd18c02628675d0a2c816449d98bda930.pngsetDaemon(true);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        workQueue=newLinkedList();//创建工作队列

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//创建poolSize的数目的工作线程并启动d18c02628675d0a2c816449d98bda930.pngfor(inti=0;i

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngnewWorkThread().start();

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     * 向工作队列添加一个新任务(向线程池提交任务).synchronized->多线程->notify

d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     *@paramtask

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicsynchronizedvoidexecute(Runnable task)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//如果线程池被关闭,则抛出IllegalStateExceptiond18c02628675d0a2c816449d98bda930.pngif(isClosed)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngthrownewIllegalStateException();

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.pngif(task!=null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            workQueue.add(task);

d18c02628675d0a2c816449d98bda930.png//唤醒正在getTask()方法中等待任务的工作线程d18c02628675d0a2c816449d98bda930.pngnotify();

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     * 从工作队列取出一个任务.工作线程调用此方法->在wait的时候可被中断,即会抛出InterruptedException

d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     *@returnd18c02628675d0a2c816449d98bda930.png     *@throwsInterruptedException

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicsynchronizedRunnable getTask()throwsInterruptedException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(workQueue.size()==0)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//如果线程池已关闭,返回nulld18c02628675d0a2c816449d98bda930.pngif(isClosed)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnnull;

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png//如果线程池未关闭且工作队列为空,则getTask调用线程则等待.并释放锁.->可能会被其他线程interrupt.d18c02628675d0a2c816449d98bda930.pngwait();

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//移除工作队列的第一个任务并返回d18c02628675d0a2c816449d98bda930.pngreturnworkQueue.removeFirst();

ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * 关闭线程池

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicsynchronizedvoidclose()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngif(!isClosed)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            isClosed=true;

d18c02628675d0a2c816449d98bda930.png//清除工作队列d18c02628675d0a2c816449d98bda930.pngworkQueue.clear();

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png//中断所有工作线程

d18c02628675d0a2c816449d98bda930.png//1.如果此时一个工作线程正在因getTask->wait->而阻塞->则会抛出IneterruptedException

d18c02628675d0a2c816449d98bda930.png//2.如果此时一个工作线程正在执行一个任务->则这个工作线程会正常执行完任务->但是在下一轮while(!isInterrupted())循环->而退出while->

d18c02628675d0a2c816449d98bda930.png//3.如果执行的任务时候工作线程被阻塞了->则也会抛出IneterruptedException->被catch了(可能被task#run catch,如task执行sleep)->然后下一轮while的时候,退出whiled18c02628675d0a2c816449d98bda930.pnginterrupt();

ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     * 关闭线程池,等待工作线程将所有的任务执行完再结束

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngpublicvoidjoin()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngsynchronized(this)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            isClosed=true;

d18c02628675d0a2c816449d98bda930.png            notifyAll();//唤醒在getTask中等待任务的工作线程->因为已经isClosed置为true->所以线程唤醒后->return null.ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//因为经过上步,已经有部分等待任务的工作线程已经结束了.

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//activeCount:Returns an estimate of the number of active threads in this thread groupd18c02628675d0a2c816449d98bda930.pngThread[] threads=newThread[activeCount()];

d18c02628675d0a2c816449d98bda930.png//enumerate:Copies into the specified array every active thread in this thread group and its subgroupsd18c02628675d0a2c816449d98bda930.pngintcount=enumerate(threads);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//调用每个active thread的join->等待所有工作线程运行结束->当前调用线程则等待->可能被interrupt->d18c02628675d0a2c816449d98bda930.pngfor(inti=0;i

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                threads[i].join();

ecedf933ec37d714bd4c2545da43add2.png            }d18c02628675d0a2c816449d98bda930.pngcatch(InterruptedException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     * 内部类:工作线程

d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     *@authorlandon

d18c02628675d0a2c816449d98bda930.png     *

ecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngprivateclassWorkThreadextendsThread

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicWorkThread()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png//java.lang.Thread.Thread(ThreadGroup group, String name)d18c02628675d0a2c816449d98bda930.pngsuper(ThreadPoolImpl.this,"WorkdThread-"+(threadID++));

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.pngpublicvoidrun()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngwhile(!isInterrupted())//判断线程是否被中断97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                Runnable task=null;

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    task=getTask();//从工作队列取任务,可能waitecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(InterruptedException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.png//如果task为null则可能表示getTask时被中断了->直接return->退出while->结束此线程d18c02628675d0a2c816449d98bda930.pngif(task==null)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturn;

ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    task.run();//运行任务,任务的执行过程中可能抛出异常.ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(Throwable t)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    t.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png                }ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        }ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.util.concurrent.TimeUnit;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *测试{@linkThreadPoolImpl}的简单使用

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-17

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassThreadPoolTester

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String

9b8a8a44dd1c74ae49c20a7cd451974e.pngargs)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngif(args.length!=2)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            System.err.println("Usage: java ThreadPoolTester numTasks poolSize");

d18c02628675d0a2c816449d98bda930.pngreturn;

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.pngintnumTasks=Integer.parseInt(args[0]);

d18c02628675d0a2c816449d98bda930.pngintpoolSize=Integer.parseInt(args[1]);

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        ThreadPoolImpl threadPool=newThreadPoolImpl(poolSize);//创建线程池

d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png//向线程池提交任务d18c02628675d0a2c816449d98bda930.pngfor(inti=0;i

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png            threadPool.execute(createTask(i));

ecedf933ec37d714bd4c2545da43add2.png        }d18c02628675d0a2c816449d98bda930.png       

d18c02628675d0a2c816449d98bda930.png        threadPool.join();//等待工作线程完成所有任务

d18c02628675d0a2c816449d98bda930.png//threadPool.close();ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.png   

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif/** *//**d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     * 创建一个简单的任务

d18c02628675d0a2c816449d98bda930.png     *

d18c02628675d0a2c816449d98bda930.png     *@paramtaskID

d18c02628675d0a2c816449d98bda930.png     *@returnecedf933ec37d714bd4c2545da43add2.png*/d18c02628675d0a2c816449d98bda930.pngprivatestaticRunnable createTask(finalinttaskID)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngreturnnewRunnable()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png           

d18c02628675d0a2c816449d98bda930.png            @Override

d18c02628675d0a2c816449d98bda930.pngpublicvoidrun()

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                System.out.println("Task"+taskID+":start");

d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.pngtry97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    TimeUnit.MILLISECONDS.sleep(500);//sleep->相当于任务的执行时间ecedf933ec37d714bd4c2545da43add2.png}d18c02628675d0a2c816449d98bda930.pngcatch(InterruptedException e)

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png                    e.printStackTrace();

ecedf933ec37d714bd4c2545da43add2.png                }d18c02628675d0a2c816449d98bda930.png               

d18c02628675d0a2c816449d98bda930.png                System.out.println("Task"+taskID+":end");

ecedf933ec37d714bd4c2545da43add2.png            }ecedf933ec37d714bd4c2545da43add2.png        };

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpackagecom.game.landon.serverSocket;

4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngimportjava.io.IOException;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.ServerSocket;

4f1150b881333f12a311ae9ef34da474.pngimportjava.net.Socket;

4f1150b881333f12a311ae9ef34da474.png

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif/** *//**d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *测试ServerSocket#accept超时

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *@authorlandon

d18c02628675d0a2c816449d98bda930.png *@since1.6.0_35

d18c02628675d0a2c816449d98bda930.png *@version1.0.0 2013-7-8

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png Exception in thread "main" java.net.SocketTimeoutException: Accept timed out

d18c02628675d0a2c816449d98bda930.png    at java.net.PlainSocketImpl.socketAccept(Native Method)

d18c02628675d0a2c816449d98bda930.png    at java.net.PlainSocketImpl.accept(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.ServerSocket.implAccept(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at java.net.ServerSocket.accept(Unknown Source)

d18c02628675d0a2c816449d98bda930.png    at com.game.landon.serverSocket.TimeoutTester.main(TimeoutTester.java:24)

d18c02628675d0a2c816449d98bda930.png *

d18c02628675d0a2c816449d98bda930.png *

8f1ba5b45633e9678d1db480c16cae3f.png*/4f1150b881333f12a311ae9ef34da474.png

4f1150b881333f12a311ae9ef34da474.pngpublicclassTimeoutTester

1fa987a29c6482f53d401256f96355eb.png

ca75c07623e1b494fee67e8f316fc310.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.pngpublicstaticvoidmain(String[] args)throwsIOException

97e794c86028c5f5b5461ae5ef440a4c.png

3c6cafce68eb941a00f1998f1d3d3aa6.gif9b8a8a44dd1c74ae49c20a7cd451974e.png{

d18c02628675d0a2c816449d98bda930.png        ServerSocket serverSocket=newServerSocket(8000);

d18c02628675d0a2c816449d98bda930.png//serverSocket.setSoTimeout(6 * 1000);//去掉这个,则accpet方法永远不会超时且一直等待下去,直到接收到了client连接才从accept返回d18c02628675d0a2c816449d98bda930.pngd18c02628675d0a2c816449d98bda930.png        Socket socket=serverSocket.accept();//如果连接请求队列为空,则server会一直等待->直到设定的超时时间d18c02628675d0a2c816449d98bda930.pngsocket.close();

ecedf933ec37d714bd4c2545da43add2.png    }8f1ba5b45633e9678d1db480c16cae3f.png}4f1150b881333f12a311ae9ef34da474.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值