我不確定這是否是我遇到的已知問題,但我無法找到一個好的搜索字符串,它會給我任何有用的結果。 無論如何,這裏的基本破敗:客戶端應用程序崩潰導致服務器崩潰? (C++)
我們有一個相對簡單的應用程序,它從源(數據庫或文件)獲取數據,並將數據通過TCP流傳輸到連接的客戶端,客戶數量;客戶端:連接到服務器,設置爲讀取(超時設置爲高於服務器心跳消息頻率)。客戶端:連接到服務器,設置爲讀取(超時設置爲高於服務器心跳消息頻率)。它阻止讀取。
服務器:一個監聽線程接受連接,然後生成一個編寫器線程從數據源讀取並寫入客戶端。寫者線程也被分離(使用boost :: thread,所以只需調用.detach()函數)。它會不定地寫入,但在寫入之前會檢查errno是否有錯誤。我們使用一個perl腳本啓動服務器,併爲每個服務器進程調用「fork」。
問題: 在看似隨機的時間,客戶端將關閉「連接終止(SUCCESFUL)」,指示遠程服務器故意關閉套接字。但是,當發生這種情況時,SERVER應用程序也會關閉,沒有任何錯誤或任何事情。它只是崩潰。
現在,爲了進一步解決問題,我們有多個由運行不同文件和不同端口的啓動腳本啓動的服務器應用程序實例。當其中一臺服務器崩潰時,所有服務器崩潰。
服務器和客戶端都使用內部創建的相同「連接」庫。它主要是C套接字調用的C++包裝器。
這裏是在連接libary爲寫一些粗糙的代碼和讀取功能:
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 2011-01-05 02:45:34
什麼操作系統?有任何核心轉儲? (去魚) – bmargulies 2011-01-05 02:46:14
@chrisaycock剛剛接受了前面的線程,謝謝。 – Nik 2011-01-05 02:49:35