http://www.blogbus.com/eastsun-logs/7762285.html
2013-10-14 23:28
435 查看
http://www.blogbus.com/eastsun-logs/7762285.html
摘自《UNIX NETWORK PROGRAMMING》chapter 6
p144
对于常见的input操作,一般分为两个步骤:
1.
wait to be ready
2.
copy data from kernel buffer to user buffer
常见的I/O模型:(参见以上步骤)
1.
阻塞I/O
用户进程执行1、2
2.
非阻塞I/O
用户轮巡1,然后执行2
3.
多路复用select、poll
用户调用select等待kernel返回,然后执行2
4.
信号驱动I/O(SIGIO)
用户设置信号处理函数(sigio)后,正常继续其他函数,当kernel返回SIGIO后,执行2
5.
异步信号I/O kernel执行1、2后通知用户进程(不常用)
# include <sys/select.h>
# include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
作用:
1.
内核扫描maxfdp1个描述符(常规情况下,系统最大值FD_SETSIZE=1024,可修改)
2.
内核查看readset, writeset, exceptset集中的描述符是否准备好
3.
等待超过timeout时间而没有描述符准备好,select返回
struct timeval {
long tv_sec;
long tv_usec;
}
注:timeval == 0
马上返回
timeval == NULL
永久阻塞
void FD_ZERO(fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_ISSET(int fd, fd_set *fdset);
注意,如循环调用select,多次检查同一描述符,必须在调用select之前重新设定初始值。select函数会在每次返回时,将没有ready的描述符所在的位清0
任何信号将使select()出错返回。而且BSD系统的select将不可能自动再启动
在标准select()中,返回后系统不会改变timeval的值,而linux系统例外。
exception condition:
当前只支持 out-of-band和the presence of control status information to be read from the master side of a pseudo terminal that has been put into
packet mode.(???)
一般的系统实现中,将fd_set设置为整数队列,每个整数元素中的一位表示为一个描述符
FD_SETSIZE定义在<sys/select.h>中,如果要更改的话,必须重新编译内核
select()的常见错误:
1.
maxfdp1必须指定为最大描述符值+1
2.
每次select返回后,都会将fd_set中的初值清0,除非该描述符已经准备好。因此,如果要重新检查描述符,必须再次赋初值
在select返回的描述符个数中,如果同一描述符同时为读、写准备好,则记数2次
早期的SVR4版本只记录1次。(bug)
select中准备好的意义:
为读准备好:
1.
在socket接受缓存中的数据 >= SO_RCVLOWAT,默认情况下,SO_RCVLOWAT=1
2.
对端写关闭,read返回0
3.
在listenfd中的complete queue
中,有entry
4.
socket出错。read返回-1
为写准备好:
1.
在socket发送缓存中的数据 >= SO_SNDLOWAT,默认情况下,SO_SNDLOWAT=2048
2.
对端读关闭,kernel返回SIGPIPE
3.
socket出错,write返回-1
注意,当socket出错时,将在readset/writeset分别赋值
使用select应该注意:
由于同时处理单个描述符的读写,可能出现此描述符的写(或读)操作已全部完成,而相对的另一个读(或写)操作还没有完成。为了获得这些数据,进程必须调用shutdown()以进行半关闭
# include <sys/socket.h>
int shutdown(int sockfd, int howto);
其中,howto可以置为SHUT_RD/SHUT_WR/SHUTRDWR
区别于close():
1.
shutdown不查看描述符计数器。直接进行半关闭
2.
close只能进行全关闭,shutdown可以选择一端或两端
服务器处理客户机请求的原则:永远不要将服务器阻塞在一个客户连接中。(可能被dos攻击)
# include <sys/select.h>
# include <signal.h>
# include <time.h>
int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *except_set, const struct timespec *timeout, const sigset_t sigmask);
摘自《UNIX NETWORK PROGRAMMING》chapter 6
p144
对于常见的input操作,一般分为两个步骤:
1.
wait to be ready
2.
copy data from kernel buffer to user buffer
常见的I/O模型:(参见以上步骤)
1.
阻塞I/O
用户进程执行1、2
2.
非阻塞I/O
用户轮巡1,然后执行2
3.
多路复用select、poll
用户调用select等待kernel返回,然后执行2
4.
信号驱动I/O(SIGIO)
用户设置信号处理函数(sigio)后,正常继续其他函数,当kernel返回SIGIO后,执行2
5.
异步信号I/O kernel执行1、2后通知用户进程(不常用)
# include <sys/select.h>
# include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
作用:
1.
内核扫描maxfdp1个描述符(常规情况下,系统最大值FD_SETSIZE=1024,可修改)
2.
内核查看readset, writeset, exceptset集中的描述符是否准备好
3.
等待超过timeout时间而没有描述符准备好,select返回
struct timeval {
long tv_sec;
long tv_usec;
}
注:timeval == 0
马上返回
timeval == NULL
永久阻塞
void FD_ZERO(fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_ISSET(int fd, fd_set *fdset);
注意,如循环调用select,多次检查同一描述符,必须在调用select之前重新设定初始值。select函数会在每次返回时,将没有ready的描述符所在的位清0
任何信号将使select()出错返回。而且BSD系统的select将不可能自动再启动
在标准select()中,返回后系统不会改变timeval的值,而linux系统例外。
exception condition:
当前只支持 out-of-band和the presence of control status information to be read from the master side of a pseudo terminal that has been put into
packet mode.(???)
一般的系统实现中,将fd_set设置为整数队列,每个整数元素中的一位表示为一个描述符
FD_SETSIZE定义在<sys/select.h>中,如果要更改的话,必须重新编译内核
select()的常见错误:
1.
maxfdp1必须指定为最大描述符值+1
2.
每次select返回后,都会将fd_set中的初值清0,除非该描述符已经准备好。因此,如果要重新检查描述符,必须再次赋初值
在select返回的描述符个数中,如果同一描述符同时为读、写准备好,则记数2次
早期的SVR4版本只记录1次。(bug)
select中准备好的意义:
为读准备好:
1.
在socket接受缓存中的数据 >= SO_RCVLOWAT,默认情况下,SO_RCVLOWAT=1
2.
对端写关闭,read返回0
3.
在listenfd中的complete queue
中,有entry
4.
socket出错。read返回-1
为写准备好:
1.
在socket发送缓存中的数据 >= SO_SNDLOWAT,默认情况下,SO_SNDLOWAT=2048
2.
对端读关闭,kernel返回SIGPIPE
3.
socket出错,write返回-1
注意,当socket出错时,将在readset/writeset分别赋值
使用select应该注意:
由于同时处理单个描述符的读写,可能出现此描述符的写(或读)操作已全部完成,而相对的另一个读(或写)操作还没有完成。为了获得这些数据,进程必须调用shutdown()以进行半关闭
# include <sys/socket.h>
int shutdown(int sockfd, int howto);
其中,howto可以置为SHUT_RD/SHUT_WR/SHUTRDWR
区别于close():
1.
shutdown不查看描述符计数器。直接进行半关闭
2.
close只能进行全关闭,shutdown可以选择一端或两端
服务器处理客户机请求的原则:永远不要将服务器阻塞在一个客户连接中。(可能被dos攻击)
# include <sys/select.h>
# include <signal.h>
# include <time.h>
int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *except_set, const struct timespec *timeout, const sigset_t sigmask);
相关文章推荐
- http协议学习系列
- HTTP请求消息格式
- Wireshark基本介绍和学习TCP三次握手
- Wireshark基本介绍和学习TCP三次握手
- android网络图片搜索——基于百度图片搜索引擎
- TCP/IP三次握手与四次挥手
- 中国移动与9 供应商构建4G网络
- iscsi存储
- eclipse ADT在线安装 https://dl-ssl.google.com/android/eclipse无法访问
- 网络子系统56_ip协议分片重组_重组分片
- 关于单机最大tcp连接数 及 linux 下 TCP 连接数修改
- 双网卡的灵活使用
- 基于TCP编程的socket
- Windows7操作系统怎样设置无线网络
- HTTP Server 'Bad Gateway' ( Android adt 或者 sdk 更想不了的解决方案)
- 网络编程释疑之:同步,异步,阻塞,非阻塞
- Struts2里ActionContext及获得HttpServletRequest对象
- Linux 网络服务
- 安卓手机网络状态收集总结
- TCP和UDP之间的区别