现在的位置: 首页 > 综合 > 正文

io端口临时记录

2018年04月02日 ⁄ 综合 ⁄ 共 2532字 ⁄ 字号 评论关闭

有了
epoll

iocp
之后,要做到高并发已经有了很好的基础了。但是真正要做好一个高并发的服务器却不是一件容易的事。 

因为 epoll iocp 只是提供了一个高效的事件通知机制,对于实现者来说,就是可以同时处理很多的句柄(比如 SocketFile等)而不用担心操作系统在事件通知上的消耗。 

但同时我们可以看到,直接使用
epoll
或者
iocp
,要求是要直接使用底层的句柄,对于一些已经封装过的 api (比如 mysql client api),是没有办法使用 epoll 或者 iocp 来处理的。如果在高并发服务器中,用到了这些 api 的话,那么就需要做一些特殊的处理,否则就会由于这些 api 会阻塞,造成整个服务器阻塞。 

 

没有任何背景的情况下,这样说有点不合适。如果说服务器是一个什么都不做的,或者只是做一个简单的 echo server 的话,那么 epoll 可能比 iocp 的并发高。但是这样的比较没什么意义。 
如果这个服务器要做一些很具体的业务处理,那么高并发的的瓶颈往往已经不在 epoll 或者 iocp 上,而是在怎么处理具体的业务上。包括怎样集成那些会造成 block api ,怎么使用更好的算法,等等。 
即使以
memcached
为例,估计用
epoll
或者
iocp
都能支持到同样的并发度。因为在并发数不断升高的时候, memcached 的瓶颈并不在 epoll 或者 iocp 的调度上,而是在于网络的传输速度和 hash table 的查找。即在达到能够区分出 epoll iocp 谁的并发度更高的时刻之前,memcached 就已经因为其他的瓶颈而无法再支持更高的并发。

 

同步与异步:

同步: ''亲自办这件事
异步:
交代要做的事情,然后忙其他的事情;'别人'(内核)会充当你的跑腿,在条件就绪后将这事办成,然后通知你(callback)

阻塞:
如果条件未就绪,''必须死等它就绪;进程睡眠
非阻塞:如果条件未就绪,''可以转身作别的事情;进程可以作任何想做的事情,不过通常是低效的轮询。

以这种理解方式,阻塞/非阻塞只对同步操作有意义;异步I/O总是意味着进程不会因为I/O陷入睡眠。

" select"归类为异步+blocking不妥,select实际上完成的只是read/write的第一部分:等待条件就绪;唯一的改进是可以等待多个条件。"select + read/write"的调用形式容易产生"系统通知我条件就绪"的假象,可实际上你不过是在条件就绪的时候醒来,然后仍然亲自动手完成了数据复制的操作。

依然使用银行的隐喻:

柜台R:只能取款
柜台W:只能存款

read: 亲自在柜台R排队(进程睡眠)
+
取款
write:
亲自在柜台W排队(进程睡眠)
+
存款

select + read/write : 亲自同时在RW两个柜台排队(进程睡眠)
+ (
存款|取款|存款+取款)

AIO : 告诉心腹小弟要取款若干,然后忙别的事情;小弟取款完毕将其如数奉上。

UNP一书中6.2节对I/O模型的分类我觉得很合理:

1).read/writeread
+ NON_BLOCK
selectsignal driven I/O 都属于同步I/O;
它们的共同特点是:将数据从内核空间复制到到用户空间的这个操作,是由用户空间的代码显式发起的。

2).只有AIO 属于
异步I/O;内核不露声色的将数据从内核空间复制到用户空间,然后通知进程。 

 

Iocp
是异步的。是读写完成时通知用户的。Epoll是可以读写的时候去通知用户的,是同步的。

 

 

http://www.javaeye.com/topic/59804      一个使用libevent的开源的服务器。

 

http://www.pczpg.com/a/2010/0319/3946.html   libevent示例/库的具体使用的方法

 

http://blog.csdn.net/dux003/archive/2010/04/08/5459560.aspx

 

使用libevent写的一个简单服务器的代码

 

 

 

 

 

 

Select

Epoll

线程消息队列。

回调函数的类。

 

 

 

 

 

 

 

 

 

非阻塞型IO

 

置一个I/O成为非阻塞很简单,只需要:

int
 val = fcntl(sockfd, F_GETFL, 0);

fcntl(sockfd,
F_SETFL, val | O_NONBLOCK);

 

第一步是获取描述字原来的属性。第2步是为描述字增加O_NONBLOCK(非阻塞)属性。

fcntl包含在头文件fcntl.h中,同时记得带上头文件unistd.h

这样的设置会影响套接字读写,比如调用read时候,如果是非阻塞描述字,read不会等待,而会立即返回。但不会影响select函数,也就是说如果你把描述字放在select中,不管描述字是阻塞还是非阻塞的,select函数都会阻塞,当然要让select函数不阻塞很简单,只用在等待时间上设置即可。

 

在没有设置非阻塞I/O情况下,有下面几种函数调用会引起阻塞:

1.read系列:包括readv,
recv, recvfrom, recvmsg
。这些函数只要描述字中没有数据就会阻塞。(一般是这样,某些情况还要视具体设置而定)。

 

2.write系列:包括writev,
send, sendto, sendmsg

 

3.accept函数:如果已连接队列中没有连接,则会引起阻塞。

 

3种如果设置了非阻塞,会立即返回,所以在返回要进行检查其返回值,鉴定是不是正确返回,还是因为非阻塞而导致的错误返回。

 

4.用于TCPconnect(不包括UDPconnect)。如果是阻塞情况,在三路握手完成之前,也就是说客户在接受到它的SYNACK之前是不会返回的。如果是设置成了非阻塞,则会立即返回,但并不表示三路握手没有成功,实际上三路握手还在进行。关于非阻塞的connect看下一篇。

 

 

 

Int val = Fcntl(sockfd,F_GETFL,0);

Fcntl(socked,F_SETFL,val|O_NONBLOCK);

 

 

 

                                                                           THREAD服务器

 

【上篇】
【下篇】

抱歉!评论已关闭.