Я не уверен, что это известная проблема, с которой я сталкиваюсь, но я не смог найти хорошую строку поиска, которая дала бы мне какие-либо полезные результаты.
Во всяком случае, вот краткое изложение:
у нас есть относительно простое приложение, которое берет данные из источника (БД или файл) и передает эти данные по TCP на подключенные клиенты по мере поступления новых данных. Это относительно небольшое количество клиентов; я бы сказал, максимум 10 клиентов на сервер, поэтому у нас есть следующий грубый дизайн:
client: подключиться к серверу, установить на чтение (с тайм-аутом, установленным на более высокую, чем частота сообщений пульса сервера). Блокирует на чтение.
сервер: один поток прослушивания, который принимает подключения, а затем порождает поток записи для чтения из источника данных и записи на клиент. Писательский поток также отсоединяется (используя boost :: thread, поэтому просто вызовите функцию .detach ()). Он блокирует запись на неопределенный срок, но перед ошибкой проверяет ошибки. Мы запускаем серверы, используя один Perl-скрипт и вызывая «fork» для каждого серверного процесса.
Проблема (и):
в случайные, казалось бы, моменты времени клиент завершает работу с «соединение прервано (SUCCESFUL)», указывающее, что удаленный сервер отключил сокет преднамеренно. Однако, когда это происходит, приложение SERVER также закрывается, без каких-либо ошибок или чего-либо еще. это просто падает
Теперь, чтобы решить эту проблему, мы имеем несколько экземпляров серверного приложения, запускаемого сценарием запуска, выполняющим разные файлы и разные порты. Когда ОДИН из серверов падает таким образом, ВСЕ серверы выходят из строя.
Сервер и клиент используют одну и ту же библиотеку «Соединение», созданную собственными силами. В основном это оболочка 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");
Любые идеи приветствуются! Заранее спасибо.