从中可以看出同样是29号文件描述符,相关系统调用记录中io.2449文件中,打开文件,可以发现相关系统调用如下:
shengjie@ubuntu:~/coding/dotnet/Io.Demo$ cat strace2/io.2449 # 截取相关系统调用 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_TCP) = 29 setsockopt(29, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 bind(29, {sa_family=AF_INET, sin_port=htons(5001), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 listen(29, 10) accept4(29, 0x7fa16c01b9e8, [16], SOCK_CLOEXEC) = -1 EAGAIN (Resource temporarily unavailable) epoll_create1(EPOLL_CLOEXEC) = 32 epoll_ctl(32, EPOLL_CTL_ADD, 29, {EPOLLIN|EPOLLOUT|EPOLLET, {u32=0, u64=0}}) = 0 accept4(29, 0x7fa16c01cd60, [16], SOCK_CLOEXEC) = -1 EAGAIN (Resource temporarily unavailable)从中我们可以发现accept4直接返回-1而不阻塞,监听在127.0.0.1:5001的socket对应的29号文件描述符最终作为epoll_ctl的参数关联到epoll_create1创建的32号文件描述符上。最终32号文件描述符会被epoll_wait阻塞,以等待连接请求。我们可以抓取epoll相关的系统调用来验证:
shengjie@ubuntu:~/coding/dotnet/Io.Demo$ grep 'epoll' strace2/ -rn strace2/io.2459:364:epoll_ctl(32, EPOLL_CTL_ADD, 35, {EPOLLIN|EPOLLOUT|EPOLLET, {u32=1, u64=1}}) = 0 strace2/io.2462:21:epoll_wait(32, [{EPOLLIN, {u32=0, u64=0}}], 1024, -1) = 1 strace2/io.2462:42:epoll_wait(32, [{EPOLLOUT, {u32=1, u64=1}}], 1024, -1) = 1 strace2/io.2462:43:epoll_wait(32, [{EPOLLIN|EPOLLOUT, {u32=1, u64=1}}], 1024, -1) = 1 strace2/io.2462:53:epoll_wait(32, strace2/io.2449:3033:epoll_create1(EPOLL_CLOEXEC) = 32 strace2/io.2449:3035:epoll_ctl(32, EPOLL_CTL_ADD, 33, {EPOLLIN|EPOLLET, {u32=4294967295, u64=18446744073709551615}}) = 0 strace2/io.2449:3061:epoll_ctl(32, EPOLL_CTL_ADD, 29, {EPOLLIN|EPOLLOUT|EPOLLET, {u32=0, u64=0}}) = 0因此我们可以断定同步非阻塞I/O的示例使用的时IO多路复用的epoll模型。
关于epoll相关命令,man命令可以查看下epoll_create1、epoll_ctl和、epoll_wait系统调用的相关说明:
shengjie@ubuntu:~/coding/dotnet/Io.Demo/strace$ man epoll_create DESCRIPTION epoll_create() creates a new epoll(7) instance. Since Linux 2.6.8, the size argument is ignored, but must be greater than zero; see NOTES below. epoll_create() returns a file descriptor referring to the new epoll instance. This file descriptor is used for all the subsequent calls to the epoll interface. shengjie@ubuntu:~/coding/dotnet/Io.Demo/strace$ man epoll_ctl DESCRIPTION This system call performs control operations on the epoll(7) instance referred to by the file descriptor epfd. It requests that the operation op be performed for the target file descriptor, fd. Valid values for the op argument are: EPOLL_CTL_ADD Register the target file descriptor fd on the epoll instance referred to by the file descriptor epfd and associate the event event with the internal file linked to fd. EPOLL_CTL_MOD Change the event event associated with the target file descriptor fd. EPOLL_CTL_DEL Remove (deregister) the target file descriptor fd from the epoll instance referred to by epfd. The event is ignored and can be NULL (but see BUGS below). shengjie@ubuntu:~/coding/dotnet/Io.Demo/strace$ man epoll_wait DESCRIPTION The epoll_wait() system call waits for events on the epoll(7) instance referred to by the file descriptor epfd. The memory area pointed to by events will contain the events that will be available for the caller. Up to maxevents are returned by epoll_wait(). The maxevents argument must be greater than zero. The timeout argument specifies the number of milliseconds that epoll_wait() will block. Time is measured against the CLOCK_MONOTONIC clock. The call will block until either: * a file descriptor delivers an event; * the call is interrupted by a signal handler; or * the timeout expires.简而言之,epoll通过创建一个新的文件描述符来替换旧的文件描述符来完成阻塞工作,当有事件或超时时通知原有文件描述符进行处理,以实现非阻塞的线程模型。
总结