У меня есть приложение, которое читает большие файлы с сервера и часто зависает на определенной машине. Он долгое время успешно работал под RHEL5.2. Мы недавно обновились до RHEL6.1, и теперь он регулярно зависает.
Я создал тестовое приложение, которое воспроизводит проблему. Он зависает примерно 98 раз из 100.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int mFD = 0;
void open_socket()
{
struct addrinfo hints, *res;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_family = AF_INET;
if (getaddrinfo("localhost", "60000", &hints, &res) != 0)
{
fprintf(stderr, "Exit %d\n", __LINE__);
exit(1);
}
mFD = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (mFD == -1)
{
fprintf(stderr, "Exit %d\n", __LINE__);
exit(1);
}
if (connect(mFD, res->ai_addr, res->ai_addrlen) < 0)
{
fprintf(stderr, "Exit %d\n", __LINE__);
exit(1);
}
freeaddrinfo(res);
}
void read_message(int size, void* data)
{
int bytesLeft = size;
int numRd = 0;
while (bytesLeft != 0)
{
fprintf(stderr, "reading %d bytes\n", bytesLeft);
/* Replacing MSG_WAITALL with 0 works fine */
int num = recv(mFD, data, bytesLeft, MSG_WAITALL);
if (num == 0)
{
break;
}
else if (num < 0 && errno != EINTR)
{
fprintf(stderr, "Exit %d\n", __LINE__);
exit(1);
}
else if (num > 0)
{
numRd += num;
data += num;
bytesLeft -= num;
fprintf(stderr, "read %d bytes - remaining = %d\n", num, bytesLeft);
}
}
fprintf(stderr, "read total of %d bytes\n", numRd);
}
int main(int argc, char **argv)
{
open_socket();
uint32_t raw_len = atoi(argv[1]);
char raw[raw_len];
read_message(raw_len, raw);
return 0;
}
Некоторые примечания из моего тестирования:
Источник тестового приложения можно найти здесь:
Захват tcpdump из Интерфейс loopback можно найти здесь:
Я воспроизвожу проблему, выполнив следующие команды:
> gcc socket_test.c -o socket_test
> perl -e 'for (1..6000000){ print "a" }' | nc -l 60000
> ./socket_test 6000000
Это видит 6000000 байтов, отправленных в тестовое приложение, которое пытается прочитать данные с помощью одного вызова recv ( ).
Я хотел бы услышать любые предложения о том, что я делаю неправильно, или какие-либо дальнейшие способы отладки проблемы.