C Многопоточность для Windows при соединении между TCPIP - PullRequest
0 голосов
/ 25 июня 2019

Я надеюсь, что смогу объяснить.Я новичок в программировании и пытаюсь отправлять и получать двоичные файлы с использованием TCPIP.Сервер должен получать несколько файлов одновременно с отправкой клиентом.Я создал файл bat для отправки на сервер.Нет проблем, если файл равен 2 или 3, но при попытке отправить около 5 файлов иногда выдает ошибку.На самом деле файл не получает должным образом.Я использовал

многопоточность Синхронизация Semaphore метода

Результат получения стороны (сервера) при печати следующий:

file name (5000.dat)
Invalid argumen(5000.dat) 
completetfile name (5120.dat)
(5120.dat) complete
file name (8192.dat)
(8192.dat) complete
file name (10240.dat)
(10240.dat) complete

Некоторый текст неправильно указан выше и каждый раз показывает другой результат.Иногда восстановить и записать файл правильно, а некоторые файлы не могут прочитать.

Мой код получающей стороны:

#include <stdio.h>
#include <winsock2.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <process.h>
#include <windows.h>
void fileReceive(void *param);
HANDLE semaphore;
HANDLE threadHandle;
  int main(int argc, char *argv[]){
     if (argc > 1) {
         goto l_param_error;
     }
     WSADATA wsaData; // Contains information about the Windows Sockets implementation
     SOCKET sock0; // creates a socket that is bound to a specific transport    service provider.
     struct sockaddr_in addr;
     struct sockaddr_in client;
     int len;
     SOCKET sock; // creates a socket that is bound to a specific transport service provider

    // Initiates use of the Winsock DLL by a process.
     int error = WSAStartup(MAKEWORD(2, 2), &wsaData);
     if (error != 0) {
         goto l_WSAIni_error;
     }
     addr.sin_family = AF_INET;// internetwork: UDP, TCP, etc.
     addr.sin_port = htons(8080);
     addr.sin_addr.S_un.S_addr = INADDR_ANY;
     sock0 = socket(AF_INET, SOCK_STREAM, 0);
        if (sock0 == INVALID_SOCKET) {
            goto l_socket_error;
        }
        // associates a local address with a socket
        if (bind(sock0, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
            goto l_bind_error;
        }

        while (1) {

            // places a socket in a state in which it is listening for an incoming connection
            if (listen(sock0, 1) != 0) {
                goto l_socket_conn_setup_error;
            }

            len = sizeof(client);
            // The accept function permits an incoming connection attempt on a socket.
            sock = accept(sock0, (struct sockaddr *)&client, &len);
            if (sock == INVALID_SOCKET) {
                goto l_error_accpet;
            }
            semaphore = CreateSemaphore(0, 1, 1, 0);

            threadHandle = (HANDLE)_beginthread(&fileReceive, 0, &sock);
            if (threadHandle == 0) {
                printf("Thread handle error");
                return 1;
            }
            CloseHandle(semaphore);
        }

        WSACleanup();
        return 0;
    }

void fileReceive(void *param) {
    int n = 0;
    int sock = *((int *)param);
    unsigned char buf[1];
    unsigned char buff[256] = { 0 };
    FILE *fp = NULL;
    memset(buff, 0, sizeof(buff));
    WaitForSingleObject(semaphore, INFINITE);
    // Receive file name
    int recvFile = recv(sock, buff, 255, 0);
    ReleaseSemaphore(semaphore, 1, 0);
    if ((recvFile == 0) || (recvFile == -1)) {
        goto l_recv_error;
    }
    fp = fopen(buff, "wb+");
    if (fp != NULL) {

        printf("file name (%s)\n", buff);

        while (n = recv(sock, &buf[0], 1, 0) > 0) {

            size_t written = fwrite(&buf, sizeof(buf), 1, fp);

            if (written != 1) {
                goto l_write_error;
            }
        }
        printf("(%s) complete\n", buff);

    }
    else {
        goto l_fp_error;
    }

    fclose(fp);
    closesocket(sock);
    _endthread();
    CloseHandle(threadHandle);
}

1 Ответ

4 голосов
/ 25 июня 2019

К сожалению, у вас длинный список проблем. Грубо говоря, кажется, что вы не понимаете TCP (это протокол потока байтов), и кажется, что вы не понимаете, какие проблемы решает синхронизация потоков и как их использовать. Учитывая это, вы пытаетесь выполнить задачу, выходящую далеко за пределы ваших возможностей, и вам следует сначала попытаться выполнить более простые задачи. Начните с кода TCP, который не использует потоки или код потока, который не использует TCP, поэтому вам не нужно сразу все делать правильно.

Вот некоторые из проблем:

  1. Вы передаете &sock в поток. Но затем измените значение sock, возможно, прежде чем поток сможет его прочитать.

  2. Вы вызываете recv по TCP-соединению, чтобы получить имя файла, и просто предполагаете, что прочитаете все и только имя файла. TCP не может «склеить» байты в сообщение. Если вы хотите отправлять и получать сообщения, вы должны определить протокол сообщений и внедрить его поверх TCP.

  3. Ваш семафор на самом деле ничего не делает. Вы не используете его для связи или синхронизации.

  4. Вы пишете 256 байтов каждый раз, когда читаете 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...