【发布时间】:2011-01-07 09:03:12
【问题描述】:
我不确定这是否是我遇到的已知问题,但我找不到可以为我提供任何有用结果的好的搜索字符串。 无论如何,这是基本的纲要:
我们有一个相对简单的应用程序,它从源(数据库或文件)获取数据,并在新数据进入时通过 TCP 将数据流式传输到连接的客户端。它的客户端数量相对较少;我会说每台服务器最多有 10 个客户端,所以我们有以下粗略的设计:
客户端:连接到服务器,设置为读取(超时设置为高于服务器心跳消息频率)。它在读取时阻塞。
服务器:一个监听线程,它接受连接,然后产生一个写入线程来从数据源读取数据并写入客户端。编写器线程也被分离(使用 boost::thread 所以只需调用 .detach() 函数)。它会无限期地阻止写入,但会在写入之前检查 errno 是否有错误。我们使用单个 perl 脚本启动服务器,并为每个服务器进程调用“fork”。
问题: 在看似随机的时间,客户端将关闭并显示“连接终止(成功)”,表明远程服务器故意关闭了套接字。但是,当这种情况发生时,服务器应用程序也会关闭,没有任何错误或任何东西。它只是崩溃。
现在,为了进一步解决问题,我们有多个服务器应用程序实例由运行不同文件和不同端口的启动脚本启动。当其中一台服务器像这样崩溃时,所有服务器都崩溃了。
服务器和客户端都使用内部创建的相同“连接”库。它主要是 C 套接字调用的 C++ 包装器。
这里是连接库中写入和读取功能的一些粗略代码:
int connectionTimeout_read = 60 * 60 * 1000;
int Socket::readUntil(char* buf, int amount) const
{
int readyFds = epoll_wait(epfd,epEvents,1,connectionTimeout_read);
if(readyFds < 0)
{
status = convertFlagToStatus(errno);
return 0;
}
if(readyFds == 0)
{
status = CONNECTION_TIMEOUT;
return 0;
}
int fd = epEvents[0].data.fd;
if( fd != socket)
{
status = CONNECTION_INCORRECT_SOCKET;
return 0;
}
int rec = recv(fd,buf,amount,MSG_WAITALL);
if(rec == 0)
status = CONNECTION_CLOSED;
else if(rec < 0)
status = convertFlagToStatus(errno);
else
status = CONNECTION_NORMAL;
lastReadBytes = rec;
return rec;
}
int Socket::write(const void* buf, int size) const
{
int readyFds = epoll_wait(epfd,epEvents,1,-1);
if(readyFds < 0)
{
status = convertFlagToStatus(errno);
return 0;
}
if(readyFds == 0)
{
status = CONNECTION_TERMINATED;
return 0;
}
int fd = epEvents[0].data.fd;
if(fd != socket)
{
status = CONNECTION_INCORRECT_SOCKET;
return 0;
}
if(epEvents[0].events != EPOLLOUT)
{
status = CONNECTION_CLOSED;
return 0;
}
int bytesWrote = ::send(socket, buf, size,0);
if(bytesWrote < 0)
status = convertFlagToStatus(errno);
lastWriteBytes = bytesWrote;
return bytesWrote;
}
任何帮助解决这个神秘的错误都会很棒!至少,我希望它不会让服务器崩溃,即使客户端崩溃(这对我来说真的很奇怪,因为没有双向通信)。
另外,作为参考,这里是服务器监听代码:
while(server.getStatus() == connection::CONNECTION_NORMAL)
{
connection::Socket s = server.listen();
if(s.getStatus() != connection::CONNECTION_NORMAL)
{
fprintf(stdout,"failed to accept a socket. error: %s\n",connection::getStatusString(s.getStatus()));
}
DATASOURCE* dataSource;
dataSource = open_datasource(XXXX); /* edited */ if(dataSource == NULL)
{
fprintf(stdout,"FATAL ERROR. DATASOURCE NOT FOUND\n");
return;
}
boost::thread fileSender(Sender(s,dataSource));
fileSender.detach();
}
...这里还有生成的子发送线程:
::signal(SIGPIPE,SIG_IGN);
//const int headerNeeds = 29;
const int BUFFERSIZE = 2000;
char buf[BUFFERSIZE];
bool running = true;
while(running)
{
memset(buf,'\0',BUFFERSIZE*sizeof(char));
unsigned int readBytes = 0;
while((readBytes = read_datasource(buf,sizeof(unsigned char),BUFFERSIZE,dataSource)) == 0)
{
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
}
socket.write(buf,readBytes);
if(socket.getStatus() != connection::CONNECTION_NORMAL)
running = false;
}
fprintf(stdout,"socket error: %s\n",connection::getStatusString(socket.getStatus()));
socket.close();
fprintf(stdout,"sender exiting...\n");
欢迎任何见解!提前致谢。
【问题讨论】:
-
@Nik 如果您希望更多人帮助您,您应该接受之前问题的一些答案。 0% 会推迟很多潜在的追求者。
-
什么操作系统?有任何核心转储吗? (去钓鱼)
-
@chrisaycock 刚刚接受了之前的帖子,谢谢。
-
@bmargulies 这是 uname -a 打印的内容:Linux krma01d 2.6.18-128.el5 #1 SMP Wed Jan 21 10:44:23 EST 2009 i686 i686 i386 GNU/Linux no core dumps, i我还用 try / catch 块包装实际代码,至少看看我是否得到任何东西,但到目前为止什么都没有......
-
在 gdb 中运行服务器并等待开发,或者确保 coresize 的 ulimit 不为零,然后查看是否获得核心转储。