分类: C/C++
2012-02-23 13:43:11
最近在项目地上发现send在发送数据时,会出现EPIPE错误,将相关的程序抽取出来,通过下面的例子进行测试。
参考网络文章:http://hi.baidu.com/tangzhenjiang/blog/item/9700f8ed7475434879f05570.html
测试环境:AIX5.3 64位、SUSE Linux Enterprise Server9
先下载unp源码: wget
tar xzvf *.tar.gz;
1、问题分析configure;make lib.
根据《UNIX Network Programming Volume 1, Third Edition: The Sockets Networking》一书对应的5.13“SIGPIPE Signal”小节,SIGPIPE错误发生于:
The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated. |
2、客户端测试程序
功能:模拟往服务端发送大量数据。
#include "unp.h" #define MAX_DATA_LEN 64*1024*1024 total_len = 0; void printf("total send bytes: %d\n", len+11); int /* while(1) { sockfd = Socket(AF_INET, SOCK_STREAM, 0); Connect(sockfd, (SA *) &servaddr, sizeof(servaddr)); cli_process(sockfd, send_len); /* do it all */ exit(0); |
功能:模拟接收客户端发送过来的大量数据。
#include "unp.h" #define MAX_DATA_LEN 64*1024*1024 char long_buff[MAX_DATA_LEN]; return total_len; void len = atol(long_buff); ret = RecvLongData(sockfd, long_buff, len); printf("total recv %d bytes\n", ret); int listenfd = Socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); Signal(SIGCHLD, SIG_IGN); for ( ; ; ) { if ( (childpid = Fork()) == 0) { /* child process */ srv_process(connfd); /* process the request */ Close(connfd); Close(connfd); /* parent closes connected socket */ |
4、编译测试
将测试程序放在unpv13e/tcpclieserv目录下,修改Makefile文件,增加如下语句:
tcpserv20: tcpserv20.o tcpcli20: tcpcli20.o |
执行测试:
# 先启动服务端 $ tcpserv20 # 查看监听服务是否启动 $ netstat -a | grep 9877 # 启动客户端测试程序 $ tcpcli20 |
测试结果
# 服务端输出 select fail: Error 0 # 表示select返回值0(超时返回) # 客户端输出 total send bytes: 1048587 |
经测试,SendData和RecvData应该不会出现问题,再次查找程序,后来发现是由于客户端先创建连接,然后在组包(组包时间太长,超过60秒),但对方服务端那边accpet连接之后,通过
select检测套接字在30秒之内是否可读,若不可读则关闭连接,这样的话,客户端组好报文后发送报文时对方已经将套接字关闭了,所以send系统调用返回EPIPE错误。最后将创建连接放置在
组包之后,即在发送之前再创建连接,解决此问题。