Socket进程处理被中断的系统调用及Accept函数返回EINTR错误处理
2014-11-02 22:51
344 查看
我们用慢系统调用来描述那些可能永远堵塞的系统调用(函数调用),如:accept,read等。永远堵塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类。例如,如果没有客户连接到服务器上,则服务器对accept的调用就没有返回保证。类似的,如果客户从未发送过一行要求服务器回射的文本,则服务器对read的调用将永不返回。其他慢系统调用的例子是对管道和终端设备的读写。有一个例外,就是磁盘IO,他一般都返回调用者。
当一个进程堵塞与慢系统调用时捕获到一个信号,等到信号处理程序返回时,系统调用可能返回一个EINTR错误。有些内核自动重启某些被中断的系统调用。为了便于移植,当我们编写一个捕获信号的程序时(多数并发服务器捕获SIGCHLD),我们必须对慢系统调用返回EINTR有所准备。
为了处理一个被中断的accept,我们对accept的调用尽心了处理,其他慢系统调用函数也可以照此思路进行处理:
第一种方法: 用continue进入for的下一次循环,从而重启被中断的系统调用;
for( ; ; )
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
}
或者 用goto来实现一样的功能,也同样让被中断的系统调用重启;
Again:
for( ; ; )
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
if(errno == EINTR)
goto Again;
else
err_sys("accept error");
}
}
另外要说明的是:
适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号切相应信号处理函数返回时,该系统调用可能返回一个EINTR错误;而有些系统内核会自动重启某些被中断的系统调用; 这点要注意;
在这段代码中,我们所做的就是自己重启被中断的系统调用,这对于accept以及其他诸如read,write,select和open这样的函数是合适的,但有一个函数我们不能自己重启:connect。如果这个函数返回INTER,我们就不能再调用他,否则返回错误。当connet被一个捕获的信号中断而且不自动重启时,我们必须调用select来等待连接完成。
最后,当我们编写处理accept返回EINTR错误的TCP服务器最终版本的时候,首先要注意幾個問題:
>>> 当fork子进程时,必须捕获SIGCHLD信号(SIGCHLD信号是子进程结束时,向内核发送的信号)
>>> 当捕获信号时,必须处理被中断的系统调用
>>> SIGCHLD的信号处理函数(sig_chld)必须正确编写,应使用waitpid函数杀死僵死进程;
以下就是 “处理accept函数返回EINTR错误的TCP服务器程序最终版本”:
#include <unp.h>
int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t child_pid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
Signal(SIGCHLD, sig_chld);
for( ; ; ) {
clilen = sizeof(cliaddr);
if( (connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0 ) {
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
if( (child_pid = Fork()) == 0 ) {
Close(listenfd);
str_cli(connfd);
exit(0);
}
Close(connfd);
}
}
最近都忙着看书,好少时间写博客和刷题了~~
当一个进程堵塞与慢系统调用时捕获到一个信号,等到信号处理程序返回时,系统调用可能返回一个EINTR错误。有些内核自动重启某些被中断的系统调用。为了便于移植,当我们编写一个捕获信号的程序时(多数并发服务器捕获SIGCHLD),我们必须对慢系统调用返回EINTR有所准备。
为了处理一个被中断的accept,我们对accept的调用尽心了处理,其他慢系统调用函数也可以照此思路进行处理:
第一种方法: 用continue进入for的下一次循环,从而重启被中断的系统调用;
for( ; ; )
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
}
或者 用goto来实现一样的功能,也同样让被中断的系统调用重启;
Again:
for( ; ; )
{
clilen = sizeof(cliaddr);
if((connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0) {
if(errno == EINTR)
goto Again;
else
err_sys("accept error");
}
}
另外要说明的是:
适用于慢系统调用的基本规则是:当阻塞于某个慢系统调用的一个进程捕获某个信号切相应信号处理函数返回时,该系统调用可能返回一个EINTR错误;而有些系统内核会自动重启某些被中断的系统调用; 这点要注意;
在这段代码中,我们所做的就是自己重启被中断的系统调用,这对于accept以及其他诸如read,write,select和open这样的函数是合适的,但有一个函数我们不能自己重启:connect。如果这个函数返回INTER,我们就不能再调用他,否则返回错误。当connet被一个捕获的信号中断而且不自动重启时,我们必须调用select来等待连接完成。
最后,当我们编写处理accept返回EINTR错误的TCP服务器最终版本的时候,首先要注意幾個問題:
>>> 当fork子进程时,必须捕获SIGCHLD信号(SIGCHLD信号是子进程结束时,向内核发送的信号)
>>> 当捕获信号时,必须处理被中断的系统调用
>>> SIGCHLD的信号处理函数(sig_chld)必须正确编写,应使用waitpid函数杀死僵死进程;
以下就是 “处理accept函数返回EINTR错误的TCP服务器程序最终版本”:
#include <unp.h>
int
main(int argc, char **argv)
{
int listenfd, connfd;
pid_t child_pid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
void sig_chld(int);
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(listenfd, (SA *)&servaddr, sizeof(servaddr));
listen(listenfd, LISTENQ);
Signal(SIGCHLD, sig_chld);
for( ; ; ) {
clilen = sizeof(cliaddr);
if( (connfd = accept(listenfd, (SA *)&cliaddr, &clilen)) < 0 ) {
if(errno == EINTR)
continue;
else
err_sys("accept error");
}
if( (child_pid = Fork()) == 0 ) {
Close(listenfd);
str_cli(connfd);
exit(0);
}
Close(connfd);
}
}
最近都忙着看书,好少时间写博客和刷题了~~
相关文章推荐
- 网络编程:处理僵死进程和被中断的系统调用
- UNIX网络编程学习(10)续--处理accept返回EINTR错误的TCP服务器程序最终(正确)版本
- 系统调用处理 暨 错误的包装函数
- linux网络编程之慢系统调用被信号中断产生EINTR错误怎么解决总结
- Linux - socket编程处理EINTR错误
- 中断处理程序、中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)
- lua学习(三)--------lua调用c++函数和简单的错误处理
- 中断处理程序、中断上下文中处理延时及一些函数的调用规则
- errno 为上面语句执行失败后产生的错误号, EINTR==4 为错误代码,意思是 被中断的系统调用
- Socket编程, 在server端read()函数调用后显示错误:Transport endpoint is not connected (犯了低级错误)
- 调用系统函数向进程发信号core
- linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式
- 调用PSAPI函数枚举系统进程
- Linux进程间通讯所使用的系统调用函数
- 中断处理程序、中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)
- Linux下调用系统函数的错误捕获
- 碰到bind错误,主程序异常,调用处理函数退出问题
- Windows平台下函数返回错误的处理
- Linux - socket编程处理EINTR错误
- unix系统后台返回服务错误产生core错误文件的处理