C - accept()接受同一个客户端两次?

时间:2014-05-15 21:29:42

标签: c multithreading sockets

我正面临着人生中最奇怪的编程问题之一。 我过去已经构建了一些服务器,客户端可以正常连接,没有任何问题。

现在我正在创建一个基本上是Web服务器的人。但是,我面临一个非常奇怪的情况(至少对我而言)。

假设您连接到localhost:8080并且accept()接受您的连接,然后代码将在一个单独的线程中处理您的请求(想法是在每个子节点上有多个分叉和线程 - 这是在另一个文件上实现的暂时但我在这个设置上也遇到了这个问题,所以......最好先简单一点。所以你的请求得到了处理,但是经过处理并且套接字被关闭并且你在浏览器上看到输出,accept()再次接受连接 - 当然没有人连接,因为只创建了一个连接。

recv之后

errno = 0(成功)(程序爆炸的地方) recv返回0但是 - 所以没有读取的字节(当然,因为连接不应该存在)

int main(int argc, char * argv[]){
  int sock;
  int fd_list[2];
  int fork_id;

  /* Socket */
  sock=create_socket(PORT);

    int i, active_n=0;
    pthread_t tvec;
    char address[BUFFSIZE];
    thread_buffer t_buffer;
    int msgsock;

    conf = read_config("./www.config");
    if(conf == NULL)
    {
        conf = (config*)malloc(sizeof(config));
        if(conf == NULL)
        {
            perror("\nError allocating configuration:");
            exit(-1);
        }

        // Set defaults
        sprintf(conf->httpdocs, DOCUMENT_ROOT);
        sprintf(conf->cgibin, CGI_ROOT);
    }

    while(cicle) {

        printf("\tWaiting for connections\n");
        // Waits for a client
        msgsock = wait_connection(sock, address);
        printf("\nSocket: %d\n", msgsock);

        t_buffer.msg = &address;
        t_buffer.sock = msgsock;
        t_buffer.conf = conf;

        /* Send socket to thread */

        if (pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer) != 0)
        {
                perror("Error creating thread: ");
                exit(-1);

        }
  }

  free(conf);

  return 0;
}

以下是使用的两个重要功能:

int create_socket(int port) {
    struct sockaddr_in server, remote;
    char buffer[BUFF];
    int sock;

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("opening stream socket");
        exit(1);
    }

    server.sin_family  = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_in))) {
        perror("binding stream socket");
        exit(1);
    }
    gethostname(buffer, BUFF);
    printf("\n\tServidor a espera de ligações.\n");
    printf("\tUse o endereço %s:%d\n\n", buffer,port);

    if (listen(sock, MAXPENDING) < 0) {
        perror("Impossível criar o socket. O servidor vai sair.\n");
        exit(1);
    }
    return(sock);
}

int wait_connection(int serversock, char *remote_address){
    int clientlen;
    int clientsock;

    struct sockaddr_in  echoclient;

    clientlen = sizeof(echoclient);
    /* Wait for client connection */
    if ((clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen)) < 0)
    {
        perror("Impossivel estabelecer ligacao ao cliente. O servidor vai sair.\n");
        exit(-1);
    }

    printf("\n11111111111111Received request - %d\n", clientsock);

    sprintf(remote_address, "%s", inet_ntoa(echoclient.sin_addr));

    return clientsock;
}

所以基本上你会看到: 11111111111111收到请求 - D

D两次都不同,所以fd肯定不同。

两次!一个接一个地被处理,然后在线程函数中的recv之后它被炸毁。有时需要处理并显示第二个,但是几秒钟之后就会显示。现在,这并不总是发生。有时它会这样做,有时却没有。

太奇怪了......

我已经推出了成为插件的可能性,导致它重新连接或者因为Apache的ab工具在一些请求之后导致相同的问题。

我想要注意的是,即使我不为客户端运行线程并只是关闭套接字,它也会发生!我已经考虑过无法完全读取标头的可能性,因此浏览器会发送另一个请求。但浏览器正确地接收数据,否则它不会显示结果正常,如果显示结果正常,则连接必须已经很好地关闭 - 否则应该出现连接重置。

任何提示?感谢您的帮助。

编辑: 如果我取出代码的起始线程部分,有时连接被接受4,5,6次......

编辑2:请注意,我知道在recv失败后程序会爆炸,我会故意退出。

2 个答案:

答案 0 :(得分:2)

这肯定是一个等待发生的错误:

  pthread_create(&tvec, NULL, thread_func, (void*)&t_buffer

您将t_buffer(一个局部变量)传递给您的线程。下次您接受客户时,可能会发生这种情况 在另一个客户端完成之前,你也会将相同的变量传递给该线程,导致很多非常不确定的行为。(例如,2个线程从同一个连接读取,双重close()读取描述符和其他奇怪的东西。)

不是将相同的局部变量传递给每个线程,而是为每个新客户端动态分配一个新的t_buffer

答案 1 :(得分:0)

  

假设...在处理完并且套接字关闭后你看到浏览器上的输出,accept()再次接受连接 - 当然没有人连接,因为只创建了一个连接。

因此,如果没有人连接,就没有什么可以接受(),所以这永远不会发生。

所以无论你看到什么,都不是。