您的位置:首页 > 理论基础 > 计算机网络

从零实现一个最精简的select网络服务模型

2017-01-25 13:24 423 查看
see more:http://wufazuce.com/select.html

前言

从零写一个基于select的最简单网络服务,从最基本的socket/bind/listen/accpet函数,了解每个函数每个参数代表的意义。

- 测试文件描述符fd是如何变化的;

- select事件触发的方式;

- 参考redis中
select
的实现;

- 读写函数
read/write
recv/send
有什么区别;

- listen中第二个参数
backlog
的作用以及表象实测;

实现select服务端

源码:https://github.com/yinnnnn/cpp_demo/blob/master/select2.c

几点实测及结论

0、文件描述符
fd
是如何变化的。

自增的,0(标准输入),1(标准输出),2(错误输出)是保留的: https://en.wikipedia.org/wiki/File_descriptor

如果中间有一个fd close了,后面的新连接会重新使用原来的fd值,所以后面接收到的client的fd不一定比前面的大。

不管是打开文件的fd还是网络请求的fd都是通用的,不会混合!

可以通过
lsof -p  433
来查看单个进程打开的文件描述符



1、每次
select
有事件触发后,再次监听必须把所有的fd重新添加到监听中,因为事件发生后fd已经被内核修改了。

FD_ZERO(&rfds);
for (int i = 0; i <= max; i++) {
//要剔除掉已经close的
printf("set fd=%d\n", i);
FD_SET(i, &rfds);
}


redis中的reset操作是通过
memcpy
实现的。

https://github.com/antirez/redis/blob/unstable/src/ae_select.c
memcpy(&state->_rfds,&state->rfds,sizeof(fd_set));
memcpy(&state->_wfds,&state->wfds,sizeof(fd_set));


2、
select
有事件触发后必须遍历整个
fd
列表(根据
FD_ISSET(i, &rfds)
)才能知道是哪些
fd
有事件触发。

3、可将bind的
fd
和接收到client请求的
fd
一起放入
select
中监听,不管是有新连接还是原来的client连接有读写事件都能触发
select
,达到真正的实时响应。

4、读写函数
read/write
recv/send
有什么区别,应该使用哪种

recv和send多一个参数来控制读写: http://blog.csdn.net/petershina/article/details/7946615

redis采用
read/write


5、backlog设置:未accpet的队列数

测试一:不是select响应的个数

如果 /proc/sys/net/ipv4/tcp_abort_on_overflow 设为 1, 直接回RST包,结束连接. (http://www.jianshu.com/p/fe2228a77429)

server端的状态是: SYN_RECV

redis默认是511

define CONFIG_DEFAULT_TCP_BACKLOG 511

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  redis select
相关文章推荐