环境:
Debian GNU/Linux 6.0
kernel 2.6.32-5-686 #1 SMP Wed Jan 12 04:01:41 UTC 2011 i686
gcc (Debian 4.4.5-10) 4.4.5
在Unix系统下,如果send在等待协议传送数据时网络断开的话,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
所以我们需要对SIGPIPE信号进行捕捉,并且在系统函数(write,read,send,recv,etc..)收到此信号时,对错误(errno==EPIPE)进行处理。
下面是我对系统函数 write() 进行的测试:
ssize_t write(int fildes, const void *buf, size_t nbyte);
1. 如果遇到对方断开,进程就会自动悄无声息的退出。
2. 如果加入信号捕捉 signal(SIGPIPE, SIG_IGN); 或者 signal(SIGPIPE, processSignal); 则会不断出现write error: Broken pipe(这时可以做异常处理,来保证不会悄悄的退出)
tcpcli.c
C语言:
#include #include #include #include #include #include #include #define MAXBUF 4096000void processSignal(
int signo)
{ printf(
"Signal is %d\n", signo);
/* signal(signo, processSignal); * add this function again is an idea,but not right */ }ssize_t writen(
int fd, const void *vptr, size_t n)
{ size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = vptr;
nleft = n;
while (
nleft > 0)
{ printf(
"Begin Writen %d\n", nleft);
if ( (
nwritten = write(
fd, ptr, nleft))
<= 0)
{ /* actually, this errno can't happen even if there is * a signal pipe */ if (
nwritten < 0 && errno == EINTR)
{ printf(
"intterupt\n");
nwritten = 0;
/* and call write() again */ } else if (
nwritten < 0 && errno == EPIPE)
{ perror(
"pipe");
return(
-1);
} else { perror(
"write error");
return(
-1);
} } nleft -= nwritten;
ptr += nwritten;
printf(
"Already write %d, left %d, errno=%d\n", nwritten, nleft, errno);
} return(n);
}void str_cli(
int sockfd)
{ char sendline[MAXBUF], recvline[MAXBUF]; while (
1)
{ memset(
sendline, 'a', sizeof(
sendline));
printf(
"Begin send %d data\n", MAXBUF);
if (
sizeof(
sendline)
!= writen(
sockfd, sendline, sizeof(
sendline)) )
break;
sleep(
3);
}}int main(
int argc, char **argv)
{ int sockfd;
struct sockaddr_in servaddr;
//signal(SIGPIPE, SIG_IGN); signal(
SIGPIPE, processSignal);
if (
argc != 2)
{ printf(
"usage: tcpcli [port]\n");
exit(
0);
} sockfd = socket(
AF_INET, SOCK_STREAM, 0);
bzero(
&servaddr, sizeof(
servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(
atoi(
argv[1])); inet_pton(
AF_INET, "127.0.0.1", &servaddr.sin_addr);
if (
connect(
sockfd, (
struct sockaddr *)
&servaddr, sizeof(
servaddr))
== -1)
{ perror(
"connect error");
exit(
1);
} str_cli(
sockfd);
return 0;
}
也贴出server.c
C语言:
#include #include #include #include #include #include #include #include #include #include #define MAXLEN 4096int init_sock()
{ int listenfd, listenq = 1024;
struct sockaddr_in servaddr;
if ( (
listenfd = socket(
AF_INET, SOCK_STREAM, 0))
== -1 )
{ perror(
"socket error");
return -1;
} int optval = 1;
if (
setsockopt(
listenfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(
optval) )
== -1)
{ perror(
"set socket reuse error");
return -1;
} /* block recv can't be used in non-block mode, or else * error "Resource temporarily unavailable" will happen
* if you want to set the socket in non-blocking mode, use
* select() or poll()to see if there is incoming data before
* calling recv() or recvfrom() */
//struct timeval t_timeout;
//t_timeout.tv_sec = 1;
//t_timeout.tv_usec = 0;
//setsockopt(listenfd, SOL_SOCKET, SO_SNDTIMEO, &t_timeout, sizeof(t_timeout));
//setsockopt(listenfd, SOL_SOCKET, SO_RCVTIMEO, &t_timeout, sizeof(t_timeout));
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(9999);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind error");
return -1;
}
if (listen(listenfd, listenq) == -1)
{
perror("listen error");
return -1;
}
return listenfd;
}
int main()
{
int sockfd, connfd;
char buff[MAXLEN];
struct sockaddr_in cliaddr;
socklen_t cliaddr_len = sizeof(cliaddr);
if ( ( sockfd = init_sock() ) == -1 )
exit(1);
for(;;)
{
if ( (connfd = accept(sockfd, (struct sockaddr *)&cliaddr, &cliaddr_len)) == -1 )
{
if (errno == EAGAIN || errno == EWOULDBLOCK)
;
else
perror("accept error");
continue;
}
if (fork() == 0)
{
/* If send, fill buffer can be wrapped to a function */
//char *cli_addr = inet_ntoa(cliaddr.sin_addr);
//memcpy(buff, cli_addr, MAXLEN);
while (1)
{
if (recv(connfd, buff, MAXLEN, 0) == -1)
{
perror("recv error");
close(connfd);
exit(0);
}
}
}
if (close(connfd) == -1)
{
perror("close error");
continue;
}
waitpid(-1, NULL, WNOHANG);
}
}
阅读(1619) | 评论(0) | 转发(1) |