c - 接受返回现有连接,导致段错误

标签 c multithreading segmentation-fault

我正在用 c 语言创建一个服务器守护进程,它接受大量同时连接,客户端将向服务器发送数据。我目前将每个客户端连接都生成到一个新线程中。我看到 accept() 有时(并非总是)返回现有连接的 ID,这(显然)会导致各种各样的问题,包括段错误。

我什至关闭了套接字选项 SO_REUSEADDR 以确保情况并非如此。每当单个客户端进行多次连续调用时,一切都很好(conid 在我下面的代码中递增 - 5、6、7、8、9 等...)。但是,每当多个客户端同时连接时,有时 conid 会重复(一次运行的示例:5,6,7,7,8,9,10,10,10,11,12 ,12, ...).

我想知道 accept() 如何返回现有连接?如果我在多个线程中调用 accept() 会很有意义,但正如您在下面看到的那样,它仅存在于主进程线程中。另一方面,我从未遇到过 select() 的这个问题,所以这可能是线程问题???在这一点上,我已经尝试了几乎所有我能想到的方法,但对我来说很明显我只是遗漏了一些东西

编辑:编辑代码以显示 mystruct 在 while 循环中没有被释放,并且(希望)提供更多见解。

编辑 #2: 根据请求,我已经发布了示例的完整源代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdarg.h>
#include <time.h>
#include <errno.h>
#include <netdb.h>


//this is my test structure
struct mystruct_ {
    int id; //only id for testing
};
typedef struct mystruct_ mystruct;

//error logging function
void merr(const char *msg, ...) {
    //get the time
    time_t t;
    time(&t);
    //grab this function's arguments
    va_list args;
    char buf[BUFSIZ];
    va_start(args,msg);
    //build the message
    vsprintf(buf,msg,args);
    //output the message
    printf(" ERROR :: %s\n",buf);
    //that's it!
    va_end(args);
}


//this function handles the threads
void *ThreadedFunction(void *arg) {
    //get the passed structure
    mystruct *test = (mystruct *)arg;
    //print conid -- this is where I am seeing the duplicates
    printf("my connection id is %d\n",test->id);
    // do some stuff, like: pull vars out of mystruct
    int nbytes;
    char buf[256];
    while(1) {
        if((nbytes=recv(test->id, buf, sizeof buf, 0)) <= 0) {
            //handle break in connection
            close(test->id);
        } else {
            //for this example, just print out data from client to make my point
            buf[nbytes] = 0;
            printf("%s",buf);
        }
    }
}

//main just sets up the connections and creates threads
int main(int argc, char *argv[])
{
    char *port = "1234";

    //get ready for connection
    struct sockaddr_storage addr;
    socklen_t addrsize = sizeof addr;
    struct addrinfo hints, *res, *ai, *p;
    int sockfd, conid, rv;
    int yes = 1;
    //
    //load up address structs with getaddrinfo():
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;     // fill in my IP for me
    if((rv = getaddrinfo(NULL, port, &hints, &ai))!= 0) {
        merr("failed to bind port '%s': %s\n",port,gai_strerror(rv));
        exit(1);
    }
    //
    //bind the port
    for(p=ai; p!=NULL; p=p->ai_next) {
        sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
        if(sockfd<0) continue;
        //setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); //commented for testing
        if(bind(sockfd,p->ai_addr,p->ai_addrlen)<0) { close(sockfd); continue; }
        break;
    }
    //if we don't have p, it means server didn't get bound
    if(p==NULL) { merr("failed to bind port '%s' (reason unknown)",port); exit(2); }
    freeaddrinfo(ai); //all done with this
    //
    // listen to the (now bounded) socket:
    if(listen(sockfd,10)==-1) { merr("listen; errmsg: \"%s\"",strerror(errno)); exit(3); }


    // bind(), listen(), etc... blah blah blah

    mystruct test[1024]; //just for testing
    printf("Ready and Listening...\n");
    while(1) {
        conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
        test[conid].id = conid;
        pthread_t p;
        pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
    }
}

最佳答案

这是坏了:

while(1) {
    conid = accept(sockfd, (struct sockaddr *)&addr, &addrsize);//get a connection
    test[conid].id = conid;
    pthread_t p;
    pthread_create(&p,NULL,ThreadedFunction,&test[conid]); //create new thread
}

pthread_t p; 在堆栈上声明一个不透明句柄,pthread_create 将填充该句柄。该句柄的生命周期必须持续到您调用 pthread_joinpthread_detach

在这种情况下,pthread_t 的存储可能会被重用,从而将参数传递给线程函数的过程搞乱了。至少,这是我的猜测。

尝试在 pthread_create 之后调用 pthread_detach

关于c - 接受返回现有连接,导致段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8599256/

相关文章:

c - 指向不返回字符串的结构的指针

c - 如何覆盖二维数组中的单词?

c - 在 C 中迭代链表时空检查行为不正确

multithreading - 如何使用带参数的函数对象启动线程

C++ linux 监控 sigsegv 进程

c - 随机访问C中函数的不定数量的参数

java - 使用信号量进行线程同步

C# 多线程 - 在线程之间移动对象

在 C 中复制无符号字符

c - fopen() 段错误,文件存在