一、标准socket
对socket编程毫无经验的新手(比如我),一开始便看NIO,虽然API是看懂了,却始终无法明白体会和标准socket编程在设计方式上的本质区别。
可以先看下如下这篇文章,把传统socket编程的服务端基础讲得比较清楚。
http://blog.csdn.net/lin49940/article/details/4398364
标准socket的服务端设计,是通过一个阻塞的监听线程和N个工作线程组成。因为每一个SOCKET连接中的操作比如read等,都是阻塞的,因此如果采用单线程处理的话,会出现如下情况:
A比B请求先到达服务端,因此线程阻塞并等待A的数据。此时B已经准备好数据但迟迟得不到处理。
而采用多工作线程的时,可能会有N个服务器线程白白将CPU的分片时间浪费在阻塞的等待中。
二、nio
再来科普下java nio的基础,如下(记得读完一二三四全部文章):
http://blog.csdn.net/wuxianglong/article/details/6604817
在nio下,服务器端线程的设计方式通常如下:
1.创建一个监听线程,新建ServerSocketChannel,调用阻塞的accept()方法监听新的客户端连接。
2.创建一个唯一的工作线程。当accept()到一个新的客户端连接SocketChannel后,调用工作线程,将该
SocketChannel注册进该工作线程的Selector中。
3.工作线程中,通过Selector.select(),等待准备好数据通讯的连接。此时上例中的A链接即使比B连接先行到达,但若B预先成为可读状态(比如A是大文件传输),则B必然会被先处理。
网上的DEMO中,通常会把1和2中的监听线程和工作线程合二为一,即将ServerSocketChannel也注册到和工作线程相同的Selector中。但我倾向于两者分开,职责分明。而且利于扩展。
三、对比
看到这里,最明显的区别,就在于nio可以降低不必要的线程开销。所谓不必要的线程开销,就是那些在标准io下进行阻塞等待的操作。 线程过多,会增加CPU分时的无意义开销。
但是,nio下是否一定只有一个工作线程呢?其实没那么极端。(二)中的工作线程,可以弱化为一个分发线程,当获取到已经做好准备读或写准备的线程时,可以创建一个线程池来进行真正的处理。但无论如何,浪费在阻塞上的无意义的线程开销没有了。
四、客户端
前文说的都是服务端,其实客户端也是一个道理。
标准io下,客户端的多个连接请求必须要用多个线程。
而nio下,可以用单线程进行处理。
下一步,打算去了解下xsocket和netty这种nio的封装框架,同时找几个使用nio的开源实例进行深入了解(比如redis的客户端JEDIS)
以上是一个socket编程纯新手的理解,希望带给那些有些迷茫的初学者一点点帮助。如有不正确的地方,请务必纠正,也算是对我这个新手的帮助 ^_^