我正在使用pthreads在C语言的
Linux上创建一个Web服务器.我用valgrind测试了泄漏和内存问题 – 所有修复.我用helgrind测试了线程问题 – 所有修复.我正在尝试
stress test.当使用helgrind运行probram时,我遇到了问题
valgrind --tool=helgrind ./chats
它只是在随机的地方死亡,文字“杀死”就像我用kill -9杀死它时一样.我有时从helgrind获得的唯一报告是该程序存在时仍保留一些锁,这在被杀时是正常的.
检查泄漏时:
valgrind --leak-check=full ./chats
它更稳定,但我设法让它死了一次,只有几百个并发连接.
我试过单独运行程序,根本无法让它崩溃.我尝试了多达250个并发连接.每个线程延迟100毫秒,以便更容易同时拥有多个连接.没有崩溃.
在所有情况下,线程和连接都不会超过10并且我看到即使有2个连接它也会崩溃,但是从来没有同时只有一个连接(包括主线程和一个帮助线程总共3个).
>问题是否可能仅在运行时发生
helgrind或者只是helgrind让它更有可能展现?
>程序被杀死的原因是什么(通过内核?)分配太多内存,文件描述符太多?
我测试了一点,我发现它只会在客户端超时并关闭连接时死掉.所以这里是检测客户端关闭套接字的代码:
void *TcpClient::run(){
int ret;
struct timeval tv;
char * buff = (char *)malloc(10001);
int br;
colorPrintf(TC_GREEN, "new client starting: %d\n", sockFd);
while(isRunning()){
tv.tv_sec = 0;
tv.tv_usec = 500*1000;
FD_SET(sockFd, &readFds);
ret = select(sockFd+1, &readFds, NULL, NULL, &tv);
if(ret < 0){
//select error
continue;
}else if(ret == 0){
// no data to read
continue;
}
br = read(sockFd, buff, 10000);
buff[br] = 0;
if (br == 0){
// client disconnected;
setRunning(false);
break;
}
if (reader != NULL){
reader->tcpRead(this, std::string(buff, br));
}else{
readBuffer.append(buff, br);
}
//printf("received: %s\n", buff);
}
free(buff);
sendFeedback((void *)1);
colorPrintf(TC_RED, "closing client socket: %d\n", sockFd);
::close(sockFd);
sockFd = -1;
return NULL;
}
// this method writes to socket
bool TcpClient::write(std::string data){
int bw;
int dataLen = data.length();
bw = ::write(sockFd, data.data(), dataLen);
if (bw != dataLen){
return false; // I don't close the socket in this case, maybe I should
}
return true;
}
附:线程是:
>主线程.这里接受连接.
>一个帮助线程,它监听信号并发送信号.它会停止应用程序的信号接收并手动轮询信号队列.原因是因为使用线程时很难处理信号.我在stackoverflow中发现了这种技术,并且它在其他项目中工作得非常好.
>客户端连接线程
完整的代码非常大,但如果有人感兴趣,我可以发布块.
更新:
我设法只用一个连接触发问题.这一切都发生在客户端线程中.这就是我做的:
>我读/解析标题.我在写入之前放置了延迟,因此客户端可以超时(导致问题).
>这里客户端超时和离开(可能关闭套接字)
>我写回标题
>我回写了html代码.
这是我回信的方式
bw = ::write(sockFd, data.data(), dataLen);
// bw is = dataLen = 108 when writing the headers
//then secondary write for HTML kills the program. there is a message before and after write()
bw = ::write(sockFd, data.data(), dataLen); // doesn't go past this point second time
更新2:得到它:)
gdb sais:
Program received signal SIGPIPE, Broken pipe.
[Switching to Thread 0x41401940 (LWP 10554)]
0x0000003ac2e0d89b in write () from /lib64/libpthread.so.0
问题1:如何取消接收此信号,我该怎么办?
问题2:如何知道远程端在写入时断开连接.在读取选择返回有数据但读取的数据为0.如何写?
最佳答案 好吧,我只需要处理SIGPIPE信号并写入返回-1 – >我关闭套接字并优雅地退出线程.奇迹般有效.
我想最简单的方法是将SIGPIPE的信号处理程序设置为SIG_IGN:
signal(SIGPIPE, SIG_IGN);
请注意,第一次写入是成功的,并没有杀死该程序.如果您有类似的问题,请检查您是写一次还是多次.如果你不熟悉gdb,那么这是怎么做的:
gdb ./your-program
> run
和gdb将告诉你关于信号和sigfaults的所有信息.