【问题标题】:Sockets with pthreads issue带有 pthreads 问题的套接字
【发布时间】:2011-09-14 20:16:28
【问题描述】:

我正在创建一个服务器/客户端回显程序。客户端读取一个字符串,发送到服务器,服务器将字符串返回给客户端。

数据结构:

typedef struct writeStruct
{
    FILE *wsock;
    int sockfd;
} writeStruct;

typedef struct readStruct
{
    FILE *rsock;
    int sockfd;
 } readStruct;

部分主要功能:

main()
{
    writeStruct *writeData;
    readStruct *readData;
    writeData = malloc(sizeof(writeData));
    readData = malloc(sizeof(readData));

    pthread_t write;
    pthread_t read;

    FILE *rsock, *wsock;

    int sockfd;
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    rsock = fdopen(sockfd, "r");
    wsock = fdopen(sockfd, "w");

    writeData->wsock = wsock;
    readData->rsock = rsock;

    writeData->sockfd = sockfd;
    readData->sockfd = sockfd;

    pthread_create(&write, NULL, writeProcess, (void*)writeData);
    pthread_create(&read, NULL, readProcess, (void*)readData);

    pthread_join(write, NULL);
    pthread_join(read, NULL);
 }

以及功能:

写函数:

void *writeProcess(void *writeData)
{
    FILE *wsock = ((writeStruct*)writeData)->wsock;
    int sockfd = ((writeStruct*)writeData)->sockfd;
    int success = 0;
    char *buf = malloc(sizeof(char) * MAXDATASIZE);

    while(fgets(buf, MAXDATASIZE, stdin) != NULL)
    {
        fputs(buf, wsock);
        fflush(wsock);
    }
    fputs(buf, wsock);
    free(buf);
    shutdown(sockfd, SHUT_WR);
}

读取函数:

void *readProcess(void *readData)
{
    FILE *rsock = ((readStruct*)readData)->rsock;
    int sockfd = ((readStruct*)readData)->sockfd;
    char *rcv, *rcvAux;
    rcv = malloc(sizeof(char) * MAXDATASIZE);
    rcvAux = malloc(sizeof(char) * MAXDATASIZE);

    rcvAux = fgets(rcv, MAXDATASIZE, rsock);
    while(rcvAux != NULL)
    {
        fflush(rsock);
        numCharsRcv += strlen(rcv);
        numLinesRcv++;
        printf("%s", rcv);
        rcvAux = fgets(rcv, MAXDATASIZE, rsock);
    }
    printf("%s", rcv);
    free(rcv);
}

碰巧 writeProcess() 工作正常,但 readProcess() 没有,显然 rsock 获得了无效的内存地址,我得到了 Segmentation Fault。


对不起,我省略了部分代码,会很长。

实际上,我正在连接套接字并且写入函数正在工作,但是当它进入读取函数时,文件指针丢失了它的引用,至少我在使用 GDB 调试时已经看到了这一点。

这个问题在我添加线程后就开始出现了,当它在单个进程上运行时它工作得很好

【问题讨论】:

  • 一方面,在打开读取的文件上调用fflush 是未定义的行为......即使它没有严重崩溃,它也不会做你想做的事。谁教你这样使用fflush
  • @R..:好点子!但是,我相信它设置了errno(EBADF?)。不确定它是否真的未定义。无论如何,我认为这是一个真正的答案。
  • 7.19.5.2:“如果流指向输出流或更新流,其中未输入最近的操作,则 fflush 函数会导致该流的任何未写入数据被传递到主机要写入文件的环境;否则,行为未定义。"
  • @R..: 哦,我错了 :) 感谢您查找!

标签: c sockets pthreads


【解决方案1】:
int sockfd;
sockfd = socket(AF_INET, SOCK_STREAM, 0);

上面创建了一个断开的 TCP 套接字。

rsock = fdopen(sockfd, "r");
wsock = fdopen(sockfd, "w");

这些打开与两个功能失调的FILE* 相同的断开连接的套接字。

您需要两个不同的连接套接字才能开始。

如果您发布的代码是一个完整的程序,我看不出它应该如何工作。 reader 和 writer 都以 fgets() 开头,这应该永远阻止它们,因为没有数据。

【讨论】:

    【解决方案2】:

    下面的第 1 点很可能是您的分段错误的真正原因:

    1. fgets 将空字符附加到存储字符串的末尾。这意味着你必须传递MAXDATASIZE-1而不是MAXDATASIZE,否则可能会发生溢出。

    2. 有些人可能会声称您的程序正在泄漏内存,因为您将fgets 的返回分配给rcvAux,它本身指向您手动分配的另一个内存地址。完成此分配后,您将无法free 它,因为分配的内存地址丢失了。

    3. 您没有检查socket()fdopen() 的返回值。而且您在退出应用程序之前不会关闭sockfd

    更新

    正如 cmets 中的 R.. 所指出的,在不可写文件描述符上使用 fflush 是未定义的行为。

    您的代码 sn-p 也不显示任何 connect()bind()+listen()+accept()。应首先连接您的套接字以执行读取和/或写入操作。检查每个操作的返回值就会发现这一点。

    【讨论】:

    • 即使在可写文件描述符上,fflush 如果它处于“读取模式”(如果最后一个操作是读取)也是 UB。要在读/写之间切换,您需要一个成功的搜索操作。
    • 嗯,对。因此,只有在保证 fd 上的最后一次操作是写入的情况下,才允许使用 fflush。现在得走了,但稍后我会更新答案以提及这一点。再次感谢! :)
    • 或者如果文件是新打开的或者刚刚成功搜索(所以它既不读取也不写入)。重要的一点是,如果有潜在的缓冲数据可供读取,fflush 是不允许的(您可以认为原因是fflush 属于写入缓冲区,而缓冲区被读取模式绑定)。
    【解决方案3】:

    我会首先检查两个 fdopen() 是否返回好的值,如果不是,则保释。

    【讨论】:

      猜你喜欢
      • 2020-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-26
      • 2020-09-30
      • 1970-01-01
      • 2020-04-13
      相关资源
      最近更新 更多