【问题标题】:error bad file descriptor while send on socket在套接字上发送时出错错误的文件描述符
【发布时间】:2018-01-22 14:20:08
【问题描述】:

我正在尝试将数据从服务器子进程发送到客户端。 我将第一个客户端 fd 存储在 ids[0] 中,第二个客户端 fd 存储在 ids[1] 中 然后我尝试将数据从第一个子进程发送到另一个客户端,反之亦然。

我收到错误的文件描述符错误。

//ids are defined at the begining as follows
    int *ids = (int *) mmap(NULL,5*sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
//accept is in a for loop...
    mysocket = accept(sock, NULL, NULL);
    printf("\nClient connected ...\n ");
    ids[i]=mysocket;
    i++;
    printf(" socket and id %d %d",mysocket,ids[i-1]);
    int pid = fork();
    if (pid == 0) {
        if (mysocket < 0) {
            perror("Error in accept");
            exit(1);
        }

    do {

        fflush(stdout);
        //clearing the bufffer
        //memset(&buf[0], 0, sizeof(buf));
        //memset(buf, sizeof(buf), '\0');
        //reading message on the socket.
        if(i==1)
        if(send(ids[1], buf, 1024,0)==-1){
            perror("error in i=1");
                    printf("%d %d %d",mysocket,ids[0],ids[1]);
        }

        if(i==2) {
            if(send(ids[0], buf, 1024,0)==-1) {
                perror("error in i=2");
                printf("%d %d %d", mysocket, ids[0], ids[1]);
            }
        }

        if (strcmp(buf, "CLOSE") == 0) {
            close(mysocket);
            break;
        }

    } while (1);

我得到的错误: i=1 中的错误:错误的文件描述符 4 4 5

值 4 和 5 是 fds 的值,并且已正确存储,我不会在任何地方关闭套接字。

【问题讨论】:

  • i 未在您的代码中声明
  • 您描述的错误意味着其中一个进程正在尝试使用与在该进程中的打开文件描述不对应的文件描述符编号。但是您的代码不包含可以重现问题的完整或可验证的示例。因此,我们只能猜测它的性质。请编辑问题以提供minimal reproducible example,这意味着不仅要添加一些位,还要修改您已有的内容。
  • 为了便于阅读和理解:: 请一致地缩进代码,在每个左大括号'{'后缩进。在每个右大括号 '}' 之前取消缩进。建议每个缩进级别为 4 个空格。
  • 感谢大家的建议。我现在正在尝试使用线程来避免共享内存问题。

标签: c sockets tcpsocket


【解决方案1】:

您的代码格式错误,我希望我能正确解释它。

ids[i]=mysocket;
i++;

如果i0,那么ids[0] 现在是有效的,ids[1] 仍然是无效的(即具有一些看起来有效但实际上不是的任意值)并且i 现在是1。使用i==1,孩子会遇到此代码(在正确格式化后):

    if(i==1)
        if(send(ids[1], buf, 1024,0)==-1){
            perror("error in i=1");
            printf("%d %d %d",mysocket,ids[0],ids[1]);
       }

如您所见,它使用send(ids[1]...。但正如上面对i==1 的解释,只有ids[0] 具有有效值,而ids[1] 中的值无效。因此sendBad file descriptor 失败。

我的猜测是您假设在主进程中创建的文件描述符实际上在所有子进程中都有效,因为您试图在子进程和主进程之间使用共享数组(使用MAP_SHARED):

int *ids = (int *) mmap(NULL,5*sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);

但是这个假设是错误的。文件描述符不会传播到所有子进程中,而只会在 fork 上传播到新子进程。这意味着您的第一个孩子将在fds[0] 中拥有一个有效的文件描述符,而第二个孩子将在fds[0]fds[1] 中拥有一个有效的文件描述符。 由于共享数组,第一个孩子将在fds[1] 中看到与第二个孩子相同的文件号这一事实并不意味着该文件号也与有效的(内核内)文件描述符相关联。

请注意,在代码中实际记录代码的意图非常有用。这样其他人可以更好地理解您的代码,并且所有人(包括您)都可以更好地验证意图是否与实现真正匹配。

【讨论】:

  • 感谢@Steffen 的建议,但 id[1] 会在一段时间后填充,我可以在打印时看到值
  • @AshwinBhoyar: 如果ids[1] 被填充,那么i 必须是&gt;=2,因为i 总是比ids[] 中的最大有效索引大一,根据您的代码显示。但是,您显示的错误发生在i==1
  • @AshwinBhoyar:我认为您的实际问题是您假设来自第二个孩子的所有文件描述符都是第一个孩子中的有效文件描述符,因为您使用共享数组。但是即使文件编号并不意味着内核中有与这些文件编号相关联的文件描述符。请参阅编辑后的帖子。如果您的代码包含您正在尝试做的事情的 cmets,这将真的很有帮助。
猜你喜欢
  • 2015-11-07
  • 1970-01-01
  • 2021-12-20
  • 2019-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-17
  • 1970-01-01
相关资源
最近更新 更多