fopen, fprintf и fclose принудительно завершают соединение сокета

У меня есть dll, которая перехватывает функцию recv сетевого приложения. Код работает просто отлично (он делает все, что должен делать), но если я добавляю выходные журналы в файл, соединение закрывается через некоторое время работы (приложение на стороне сервера выдает ошибку «Существующее соединение было принудительно закрыто удаленным хозяин").

Это время даже не всегда одинаково, иногда оно закрывается почти при инициализации соединения, в других случаях я могу использовать соединение в течение нескольких секунд, прежде чем оно будет закрыто. Он не выдает никаких сообщений об ошибках или предупреждений. Если я удалю код журнала, приложение будет работать нормально. Любая идея, почему это происходит? Я запускаю его в Windows 8 x64

Кроме того, даже стирая код журнала, соединение продолжает закрываться в Windows XP x32.

Вот код хука recv:

int __stdcall NewRecv(SOCKET socket, char *data, int datalen, int flags) {
    int result = 0;
    if(!IsLoginServerPacket(&socket)) {

        INT size = 0,opcode = 0,temp = 0,writer = 0,second_op = 0;
        do {
            size = 0;
            second_op = 0;
            temp = 0;
            writer = 0;

            while(temp < 2) {
                temp += recvPacket(socket,recv_gs_buffer+writer,2 - temp,flags);
                writer += temp;
            }

            size = (*(SHORT*)recv_gs_buffer) & 0xffff;

            // THIS IS THE LOG CODE
            FILE *f = fopen("debug.txt", "a");
            fprintf(f, "datalen=%d, size=%d\n", datalen, size);
            fclose(f);

            while(temp < size) {
                temp += recvPacket(socket,recv_gs_buffer+writer,size - temp,flags);
                writer += temp;
            }

            Decrypt(&gs_crypt,recv_gs_buffer+2,size-2);
            opcode = (*(recv_gs_buffer+2) & 0xff);

            if(opcode == EXTENDED_PROTOCOL) {
                second_op = *(SHORT*)(recv_gs_buffer + 3);
                second_op &= 0xffff;
                HandleGameServerPacket(second_op,recv_gs_buffer+2,size-2);
            }
        } while(second_op == 0x8a || second_op == 0x8b);

        if(opcode == 0x00) {
            SetKey(recv_gs_buffer+4,&gs_crypt);
            SetKey(recv_gs_buffer+4,&client_crypt);
        } else
            Crypt(&client_crypt,recv_gs_buffer+2,size-2);

        int i = 0;
        while(i < size) {
            data[i] = recv_gs_buffer[i];
            i++;
        }
        //memcpy(data,recv_gs_buffer,size);
        result = size;
    } else
        result = recvPacket(socket,data,datalen,flags);

    return result;
}

person Nadir    schedule 04.08.2013    source источник
comment
Я заметил одну вещь: вы передаете datalen, но затем записываете в data[i], используя size в качестве длины блока, для которой установлено значение 0xffff.   -  person Devolus    schedule 04.08.2013
comment
да, но параметр datalen всегда имеет значение 16384, а самый большой пакет, отправленный сервером, не превышает 300 байт, поэтому я думаю, что он вообще не должен переполняться.   -  person Nadir    schedule 04.08.2013
comment
Возможно ли, что простое открытие файла, запись в него и его закрытие вызывают достаточную задержку (возможно, иногда?), чтобы заставить приложение думать, что что-то не так (или вызывать отбрасывание пакетов, что, в свою очередь, приводит к тому, что приложение чтобы быть недовольным?Вы пробовали просто открыть файл в начале дня, а затем писать, не закрывая файл (или уменьшая количество плиток, открываемых/закрывающихся файлом)?   -  person Mats Petersson    schedule 04.08.2013
comment
да, я так проверял, но все равно та же проблема   -  person Nadir    schedule 04.08.2013
comment
У меня была похожая проблема на vС++; в моем случае запись в поток с использованием printf завершала программу между получением семафора и его освобождением. Похоже, что переключателю контекста чего-то не хватает (сокета, разделяемой памяти или обработчика семафора) при обработке прерывания. Я был на vm (используя одно ядро).   -  person sgun    schedule 04.08.2013
comment
Вы ищете не тот конец провода для этой проблемы. Сокет закрыл сервер, а не клиент.   -  person Hans Passant    schedule 04.08.2013
comment
Итак, сервер чувствует тайм-аут или что-то в этом роде?   -  person Nadir    schedule 04.08.2013
comment
Сервер настроен на неблокирующий режим, что может быть?   -  person Nadir    schedule 05.08.2013


Ответы (1)


Я просто нашел проблему и ее решение.

Введенное приложение настраивало сокеты в неблокирующем режиме. Любая небольшая задержка приводила к выдаче WSAEWOULDBLOCK (код ошибки 10035). Все, что мне нужно было сделать, чтобы исправить это, это повторить запрос recv, если я получу какую-либо ошибку.

INT val = 0;
while(temp < 2) {
    val = recvPacket(socket,recv_gs_buffer+writer,2 - temp,flags);
    if(val > 0) {
        temp += val;
                writer += temp;
    }
}

А также

val = 0;
while(temp < size) {
    val = recvPacket(socket,recv_gs_buffer+writer,size - temp,flags);
    if(val > 0) {
        temp += val;
                writer += temp;
    }
}
person Nadir    schedule 05.08.2013