【问题标题】:bad file descriptor: error on accept()错误的文件描述符:accept() 上的错误
【发布时间】:2016-05-25 10:58:07
【问题描述】:

我正在尝试编写一个简单的聊天应用程序,其中客户端从服务器接收字符串并发送一条新消息,该消息将传递给下一个连接的客户端。我是套接字编程的新手,我真的不明白为什么会发生这个错误。客户端发送他的缓冲区后,服务器通知accept() 上的错误(返回-1)和错误的文件描述符。这是在服务器上运行的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

void error(char *msg) {
    perror(msg);
    exit(1);
}

int main (int argc, char *argv[] ) {

    if ( argc < 2 ) {
        error("ERROR, no port provided\n");
    }

    int sockfd;
    struct sockaddr_in serv_addr, cli_addr;
    int cli_len, portno;
    char message[256];
    pid_t pid;
    int n;

    portno = atoi( argv[1] );
    bzero( (char*)&serv_addr, sizeof(serv_addr) );
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons( portno );

    sockfd = socket( AF_INET, SOCK_STREAM, 0 );

    n =  bind ( sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr) );
    if ( n < 0 ) {
        error("ERROR on binding\n");
    }

    listen( sockfd, 5 );

    do {
        cli_len = sizeof(cli_addr);

        int newsockfd;
        newsockfd = accept( sockfd,(struct sockaddr*)&cli_addr,(socklen_t *)&cli_len);
        if ( newsockfd < 0 ) {
            printf("%i", newsockfd);
            error("ERROR on accept\n");

        }

        pid = fork();
        if( pid == 0 ) {

            close( sockfd );
            sockfd = -1;

            n = send( newsockfd, message, strlen(message), 0);
            if ( n < 0 ) error("ERROR sending\n");

            bzero(message, 256);

            n = recv( newsockfd, message, 256, 0);
            if ( n < 0 ) error("ERROR receiving\n");

            close( newsockfd );
            newsockfd = -1;

        } 

    }
    while( 1 );

    return 0;
}

【问题讨论】:

  • cli_len 应该是 socklen_t 类型,而不是 int。类型转换隐藏了 x86_64 上的潜在问题,其中 int 可以是 32 位,但其他与大小相关的类型可以是 64 位。
  • 您没有正确报告错误。您需要致电perror()strerror() 做任何其他可能改变errno 的事情,例如printf()。修复,重新测试,...
  • 问题2,完成后孩子应该调用exit,否则孩子和父母都会在accept()中争吵;-)

标签: c sockets


【解决方案1】:

分叉的孩子应该在read() 之后结束,但事实并非如此。它继续循环。什么可能不是你的意图。

然后孩子调用accept() 传递-1 作为套接字描述符。 -1 不是有效的套接字描述符。

    accept(sockfd, ...

孩子在这里将sockfd 设置为-1

    pid = fork();
    if( pid == 0 ) {

        close( sockfd );
        sockfd = -1;

这样做,socket() 返回的有效套接字描述符被覆盖,丢失。

因此,您观察到的错误不是来自您的侦听服务器进程,而是来自分叉的子进程。

要解决此问题,请在子级内部添加对 exit() 的调用,如下所示:

        ...
        newsockfd = -1;
        exit(EXIT_SUCCESS);
      }

这个int cli_len; 应该是socklen_t cli_len;。并且应该删除调用accept()cli_len 的演员表。 不要盲目抛弃错误!

【讨论】:

    【解决方案2】:

    如果fork() 的结果为零,您需要使用接受的套接字执行 I/O然后退出进程。目前,您允许在关闭侦听套接字后在子进程中重复接受循环。

    【讨论】:

      猜你喜欢
      • 2021-12-20
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 2011-09-08
      • 1970-01-01
      • 2017-03-25
      • 1970-01-01
      相关资源
      最近更新 更多