socket分析

一:传统socket分析

1.

Server.accept();传统socket是会阻塞等待客户端请求的,读取时也是会阻塞的。

InputStream.read(bytes)(读取阻塞)

问题是,原始的写法并不是多线程并发的,在处理某个正被阻塞的请求时是不会再去处理新进入的请求的。那如何解决多线程并发的问题呢?用ExecutorService线程池的方式是一种方法。

那么问题又来啦,一个请求就分配一个服务生,这样的资源消耗如果做长连接的服务还是有些头疼吧。只不过从历史引进方面,短连接还是能处理的,比如以前的tomcat就采用了一问一答的形式,基本很少出现独占的情况,一个线程是可以处理多个任务的。

总结:单线程时只有一个客户端,线程池时可有多个客户端,只是很消耗资源,不适合做长连接的服务器,短连接的应答模式如tomcat还是能用一下的。

2.NIO

initServer(serversocket 绑定端口)

然后listen(selector是阻塞的,获得key,将处理selector key,会注册一个socket事件,selector将不会不断阻塞)

ServerSocketChannel ServerSocket(餐厅)

SocketChannel Socket(客户)

Selector是核心(服务生)

NIO可以实现单线程为多个客户服务,传统IO是不适应的。传统IO是一个客人对应一个服务员。

NIO可以用餐厅服务生点菜的方式理解,一个服务生可以被多个客户共享。只要一个服务生不断的等待被调用,接待客人或想用客人点菜。NIO是netty的基础,否则netty是不好看懂的。明白的是思想,而不是别的。

SimpleChannelHandler处理消息的接收和发放,检测消息是否是恶意频繁访问,下线异常处理和数据清理等业务链接控制,上图的boss,worker一个是监听端口,一个是控制选择器的。

Netty整个线程工作的原理:

Netty客户端写法,和服务端写法相似,客户端,编码解码器,没有连接的话是不能disconnected的,会直接close.连的话,并不只是连一次。

分析下netty的原码,netty的工作原理,要知其然和所以然。

原始IO,一个线程服务一个socket客户。NIO可以一个线程服务多个客户端,selector可以选择多个客户端,只要selector打开相应的channel。我觉得就是把单线程的长连接占用别让它空闲,充分的利用它来监听多个可能的请求,选择合适的,然后进行业务处理。而不像IO那样是one2one绑定占用式的服务。

NIO,1个线程+selector服务多个客人

NIO问题,说一个IO是否阻塞,不是看执行是否停在那里了,而是是否会立刻返回数据,selector.wakeup()可以唤醒,所以基本是没有阻塞的情况。Selector允许关注某些事情,事情关注了才会去响应。(比如SelectorKey.Write).

Netty,hadoop,dubbo,akka用在什么地方,底层RPC通信基本都是基于netty。部分游戏服务器已经开始使用netty.netty是个线程消息数据获得等很好的框架。开始我们NIO并不是多线程的。我们创建个线程池,处理时扔到线程池里面。对IO的操作方式弄个线程池就可以了。ExecutorService es = Executors.newCachedThreadPool(); es.execute(new Runnable(){ public void run(){ handler(socket);}});但是多线程时却是报错的。一个NIO有多个selector, 而且一个selector可以注册多个服务。如果餐厅扩大,一个服务生可以按片来监督和管理自己的负责的区域,一个餐厅可以被分成多个区域。一个并发很好的思想是不会直接主动的调用任务而是往任务队列中压入任务。Netty的工作原理,基本是自己的对象执行自己的任务,放入队列任务,从队列中取出对应的任务,注册,wakeup后执行。

Netty源码分析:

1.       看代码直接引入了项目,然后打印些东西进行跟踪。处理些任务队列,处理,分配原理。

2.       学到了栈顶的执行,学到了断点设置属性。先调用的在栈底。

3.       先把基础的弄懂。

Netty回顾,客户端连接服务端时,如果连接成功会有disconnected,然后closed。如果没有连接成功直接就closed。

线程池:内部是有多个队列放线程的,执行时是并发执行的

1个htread+队列=一个单线程线程池=》线程安全,任务是线性串行执行的。

单客户端,多连接如何维护呢?

A.      对象池

B.      对象组

对象池用在什么地方呢?当单个对象线程不安全,或多线程并发产生阻塞效应的时候可以尝试用对象池的设计。比如数据库连接池,不是线程安全,或并发会产生阻塞效应。

还有一种设计叫对象组设计方式,这种方式并不移除对象,所以就有多个线程访问同个对象的可能,所以要求这个对象要有并发的能力。那么客户端用channel写数据时是否线程安全呢,SingleThreadEventExecutor是单线程+线程池,是串行执行的,不会有并发问题。

         使用ip,可能出现断网重连的可能。

Netty心跳

1.用户长时没读写,需要断掉会话,这个时候检测状态,学习idleStateHandler

猜你喜欢

转载自my.oschina.net/u/1052786/blog/1559955