【问题标题】:C Multithreading for Windows while connection between TCPIPTCPIP之间连接时Windows的C多线程
【发布时间】:2019-11-06 22:40:24
【问题描述】:

我希望我能解释一下。我是 c 编程的新手,并尝试使用 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);
}

【问题讨论】:

  • 信号量是干什么用的?
  • 您希望接收方如何知道文件名的结束位置和文件数据的开始位置?另外,为什么每次只收到一个字节时写入 256 个字节?为什么在while 循环内调用listen?我也想知道你认为信号量的用途是什么。
  • 将 sock 与线程通信的方式很糟糕 - 在线程可以取消引用指针之前,已接受的 sock 可能会被新的套接字覆盖。此外,通常滥用 TCP 字节流。可能是其他东西。
  • @MartinJames semphore 是多线程同步的方法之一
  • @Niksankarkee 是的,但具体来说它在这里做什么?为什么你认为线程需要同步,你认为信号量以什么方式同步它们?比如为什么线程调用recv后释放信号量?

标签: c windows multithreading visual-studio


【解决方案1】:

很遗憾,您有一长串问题。说白了就是看不懂TCP(它是字节流协议),看不懂线程同步解决了什么问题,怎么使用。鉴于此,您正在尝试一项超出您能力范围的任务,应该首先尝试更简单的任务。从不使用线程的 TCP 代码或不使用 TCP 的线程代码开始,这样您就不必一次搞定所有事情。

这里有一些问题:

  1. 您将&amp;sock 传递给线程。但随后更改sock 的值,可能在线程读取它之前。

  2. 您在 TCP 连接上调用 recv 以获取文件名,并假设您将读取所有且仅读取文件名。 TCP 无法将字节“粘合”到一条消息中。如果要发送和接收消息,必须定义一个消息协议并在 TCP 之上实现它。

  3. 您的信号量实际上并没有做任何事情。您不使用它来通信或同步任何东西。

  4. 每次读取 1 时写入 256 个字节。

【讨论】:

  • 在这个程序之前,我创建了没有线程的 TCPIP 程序,一次发送和接收一个文件没有任何问题。并且还使用此程序可以正确接收一个文件。但是在接收多个文件时,一些文件被接收,而有些不是这就是我使用同步的原因。我想我应该更多地研究线程。感谢大卫的支持
  • 你的 1 个数字猜对了,我将 &amp;sock 传递给了线程,现在通过更正 sock 将值更改为线程,printf 没有错位,并且多个文件也收到了..非常感谢
  • 你还是应该修复其他错误!
猜你喜欢
  • 2010-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多