Как правильно отправлять файлы в клиент-серверное приложение? - PullRequest
1 голос
/ 10 марта 2019

Я хочу создать клиент-серверное приложение, когда клиент может зарегистрироваться, войти в систему, передать сообщение другим клиентам, отправить файлы и так далее. Все, кроме отправки файлов, работает довольно хорошо.

В клиентском приложении я создал отдельный поток для каждого файла, который я хочу отправить. Чтение файла успешно, но отправка не так хороша. Я должен сделать поток в проекте сервера для получения байтов, отправленных клиентом?

Я хочу, чтобы отправка файлов была асинхронной, чтобы другие клиенты могли общаться с сервером, когда сервер получает файл. Поток для чтения файла и отправки данных на сервер:

DWORD WINAPI SendFile(LPVOID param)
{
    FileStruct* fileStruct = (FileStruct*)param;
    CM_DATA_BUFFER* dataToSend = NULL;
    CM_SIZE dataToSendSize = MAXLENGTH;
    CM_ERROR error;
    CM_SIZE sendBytesCount = 0;
    FILE* f = fopen(fileStruct->filePath, "rb");
    char buffer[2];
    fseek(f, 0, SEEK_SET);
    if (f == NULL)
    {
        perror((const char*)f);
    }
    char messageBuffer[10];
    while (fread(buffer, 1, 1, f) == 1)
    {
        *(int*)messageBuffer = SENDTYPE;
        messageBuffer[4] = buffer[0];
        messageBuffer[5] = 0;

        dataToSend = NULL;
        error = CreateDataBuffer(&dataToSend, dataToSendSize);
        if (CM_IS_ERROR(error))
        {
            _tprintf_s(TEXT("Failed to create SEND data buffer with err-code=0x%X!\n"), error);
            DestroyClient(fileStruct->client);
            UninitCommunicationModule();
            return (DWORD)-1;
        }

        error = CopyDataIntoBuffer(dataToSend, (const CM_BYTE*)messageBuffer, (CM_SIZE)strlen(messageBuffer));
        if (CM_IS_ERROR(error))
        {
            _tprintf_s(TEXT("CopyDataIntoBuffer failed with err-code=0x%X!\n"), error);
            DestroyDataBuffer(dataToSend);
            DestroyClient(fileStruct->client);
            UninitCommunicationModule();
            return (DWORD)-1;
        }
        error = SendDataToServer(fileStruct->client, dataToSend, &sendBytesCount);
        if (CM_IS_ERROR(error))
        {
            _tprintf_s(TEXT("SendDataToServer failed with err-code=0x%X!\n"), error);
            DestroyDataBuffer(dataToSend);
            DestroyClient(fileStruct->client);
            UninitCommunicationModule();
            return (DWORD)-1;
        }
        DestroyDataBuffer(dataToSend);
    }
    return (DWORD)0;

}

Вот часть кода с сервера потоков, отвечающая за получение данных:

while ((error = ReceiveDataFromClient(newClient, receivedData, &numberOfBytesRead)) == 0)
    {
        message = (char*)receivedData->DataBuffer;
        if (CM_IS_ERROR(error))
        {
            _tprintf_s(TEXT("ReceiveDataFormServer failed with err-code=0x%X!\n"), error);
            DestroyDataBuffer(sendData);
            DestroyDataBuffer(receivedData);
            break;
        }
        type = *(int*)receivedData->DataBuffer;
        printf("%x\n", type);
        if (type == SENDTYPE)
        {
            printf("%c", (char)receivedData->DataBuffer[4]);
            DestroyDataBuffer(receivedData);
            receivedData = NULL;
            error = CreateDataBuffer(&receivedData, MAXLENGTH);
            if (CM_IS_ERROR(error))
            {
                _tprintf_s(TEXT("Creating receivedDataBuffer failed with err-code =0x%X!\n"), error);
                UninitCommunicationModule();
            }
            continue;
        }

Это функция ReceiveDataFromClient:

CM_ERROR ReceiveDataFromClient(CM_SERVER_CLIENT* Client, CM_DATA_BUFFER* DataBufferToReceive, CM_SIZE* SuccessfullyReceivedBytesCount)
{
    if (Client == NULL || DataBufferToReceive == NULL || SuccessfullyReceivedBytesCount == NULL)
        return CM_INVALID_PARAMETER;

    CM_ERROR error = ReceiveData(
        Client->ClientConnection
        , DataBufferToReceive->DataBuffer
        , DataBufferToReceive->DataBufferSize
        , SuccessfullyReceivedBytesCount
    );
    if (CM_IS_ERROR(error))
        return error;

    DataBufferToReceive->UsedBufferSize = *SuccessfullyReceivedBytesCount;

    return error;
} 

А это функция ReceiveData:

CM_ERROR ReceiveData(CM_CONNECTION* Connection, CM_BYTE* OutputDataBuffer, CM_SIZE OutputDataBufferSize, CM_SIZE* SuccessfullyReceivedBytesCount)
{
    if (Connection == NULL)
        return CM_INVALID_CONNECTION;

    if (INVALID_SOCKET == Connection->ConnectionSocket)
        return CM_INVALID_PARAMETER;

    int receiveResult = recv(Connection->ConnectionSocket, (char*) OutputDataBuffer, OutputDataBufferSize, 0);
    if (receiveResult == SOCKET_ERROR)
    {
        CM_LOG_ERROR(TEXT("recv failed with err-code=0x%X!"), WSAGetLastError());
        return CM_CONNECTION_RECEIVE_FAILED;
    }

    if (receiveResult == 0)
        return CM_CONNECTION_TERMINATED;

    *SuccessfullyReceivedBytesCount = (CM_SIZE)receiveResult;

    return CM_SUCCESS;
}
...