Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   [решено] WinSock (http://forum.oszone.net/showthread.php?t=146677)

ganselo 30-07-2009 18:59 1181739

WinSock
 
Здравствуйте!
Есть сервер на котором установлена прога (серверная часть). Клиенты посылают запросы серверу на скачку файлов.
Пытаюсь написать клиентскую часть, но возникают проблемы с приёмом файлов. Вот кусок кода, где осуществляется приём и запись:
Код:


//command[0] = "File", command[1] = FileName - заголовок приходящий от сервера.
if(command[0] == "File")
{
      //создаём поток для записи файла
      HANDLE hThread = CreateThread(NULL, 0, DownloadThread, command[1].c_str(), 0, NULL);
      if(hThread == INVALID_HANDLE_VALUE)
      {
            ....
      }
      ....
      CloseHandle(hThread);
}
//===================================================================
DWORD WINAPI DownloadThread(LPVOID lpParam)
{
      LPTSTR Param = (LPTSTR)lpParam;
      char recvBuff[4097];
      SOCKET sock;
      HANDLE hFile;
      OVERLAPPED ovlp;

      char FileName[MAX_PATH] = "C:\\";
      strcat(FileName, Param);
      .....
      .....
      //Создаём файл
      hFile = CreateFile(FileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                                  NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
      //запускаем цикл, где считываем сообщения от сервера.
      while(1)
      {
            int ret = recv(sock, recvBuff, sizeof(recvBuff), 0);
            if(ret == 0 || ret == SOCKET_ERROR) break;

            recvBuff[ret] = '\0';

            ovlp.Offset = GetFileSize(hFile, 0);
            ovlp.OffsetHigh = 0;
            ovlp.hEvent = NULL;

            //записываем в файл
            WriteFile(hFile, recvBuff, strlen(recvBuff), 0, &ovlp);
      }
        CloseHandle(hFile);
        closesocket(sock);
      .....
}

Проблема в том, что текстовые файлы приходят нормально, а бинарные нет.
Точно знаю, что серверная часть работает нормально и серверная часть отсылает файл с помощью функции TransmitFile (mswsock.h).
Кто нибуть знает почему не правильно приходят или я не так записываю бинарные файлы?

pva 31-07-2009 07:58 1182146

Используешь асинхронную операцию на файлах и забываешь синхронизировать запись/чтение. Сделай двойную буфферизацию с синхронизацией или пиши синхронно:
Код:

// Асинхронное с синхронизацией

char mem[0x2000];
OVERLAPPED ovlp[2];
...
char *buf1=mem, *buf2=mem+0x1000;

for(bool is_active = true; is_active; std::swap(buf1, buf2))
{
    int ret = recv(sock, buf1, 0x1000, 0);
    ...
    // т.к. ovlp.hEvent=0 при попытке записать что-то в файл одновременно
    // (в разные концы файла например), могут происходить неверные срабатывания
    // функции GetOverlappedResult. SDK рекомендует использовать hEvent
    unsigned long dw_transferred = 0;
    GetOverlappedResult(hFile, &ovlp, &dw_transferred, true);
    WriteFile(hFile, recvBuff, strlen(buf1), 0, &ovlp);
}

// синхронное

for(bool is_active = true; is_active;)
{
    int ret = recv(sock, buf, 0x1000, 0);
    ...
    unsigned long dw_transferred = 0;
    WriteFile(hFile, recvBuff, strlen(buf), &dw_transferred, 0);
}


ganselo 31-07-2009 11:50 1182288

Решил использовать синхронную операцию на файлах. Всё равно не работало на бинарных файлах...
После второй выпитой бутылки пива, всё таки решил эту проблему.
Оказалось всё дело в функции strlen()
Код:

WriteFile(hFile, recvBuff, strlen(recvBuff), 0, 0);
Если файл текстовый то strlen() срабатывает нормально, а если бинарные данные то результат был непредсказуемый (иной раз strlen() возвращала результат в 2 раза больше нужного).
А нужно было так:
Код:

while(1)
{
    int ret = recv(sock, recvBuff, sizeof(recvBuff), 0); //recv(...) возвращает длину данных, записанных в recvBuff
    ....
    WriteFile(hFile, recvBuff, ret, 0, 0);
}



Время: 18:34.

Время: 18:34.
© OSzone.net 2001-