C socket和malloc / mutex崩溃

时间:2017-03-29 14:48:00

标签: c multithreading sockets pointers

我试图在C中构建一个多客户端和多服务器程序。让我解释一下: 1)N-clients可以连接和发送信息(s_packets) 2)N服务器可以连接并获取此信息(是的,我们的外部服务器将连接到该程序以接收客户端发送的数据) 3)连接到我程序的服务器不会发送任何内容,只接收客户端发送的数据。

现在问题是:我在函数malloc()中遇到随机错误。这就是我正在做的事情: 在main函数中,我创建了我需要的所有互斥锁并启动了2个线程:waitNewClients和waitNewServers。 waitNewClients将等待(接受)客户端连接,当客户端连接时,启动一个名为handle_connection的线程。 waitNewServers也会这样做,但是当连接服务器时,创建了一个名为server_handle的新线程。

在全球范围内,我有这个:

     struct s_packets {
        char callsign[30];
        char c_key[33];
        struct s_packets *next;
    };

    struct s_servers {
        int8_t               active;
        char                ip[50];
        int32_t             port;
        pthread_t           s_thread;
        int                 *socket;
        struct s_packets    *packets;
    };
struct s_servers serverList[MAX_SERVERS];

这是在连接时创建新客户端的功能:

void *waitNewClients(void *arg) {

    int socket_desc, client_sock, c, *new_sock;
    struct sockaddr_in server, client;
    signal(SIGCHLD, SIG_IGN);
    //Create socket
    socket_desc = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_desc == -1) {
        printf("Could not create socket");
    }
    puts("Socket created");

    //Prepare the sockaddr_in structure
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(30008);

    //Bind
    if (bind(socket_desc, (struct sockaddr *) &server, sizeof (server)) < 0) {
        perror("bind failed. Error");
        exit(1);
    }
    puts("bind done");

    //Listen
    listen(socket_desc, 3);

    //Accept and incoming connection
    puts("Waiting for incoming connections...");
    c = sizeof (struct sockaddr_in);


    while ((client_sock = accept(socket_desc, (struct sockaddr *) &client, (socklen_t*) & c))) {

        pthread_t thread_id;
        new_sock = (int *) malloc(1);
        *new_sock = client_sock;

        // puts("Connection accepted");
        printf("New connection , socket fd is %d , ip is : %s , port : %d \n", client_sock, inet_ntoa(client.sin_addr), ntohs(client.sin_port));
        enable_keepalive(client_sock);

        if (pthread_create(&thread_id, NULL, connection_handler, (void*) new_sock) < 0) {
            perror("could not create thread");
            exit(1);
        }

        //Now join the thread , so that we dont terminate before the thread
        // pthread_join(thread_id, NULL);
        puts("Handler assigned");
    }

    if (client_sock < 0) {
        perror("accept failed");
        exit(1);
    }

    return NULL;

}

现在,在connection_handle中,代码是:

void *connection_handler(void *socket_desc) {
    //Get the socket descriptor
    int sock = *(int*) socket_desc;
    size_t buf_idx = 0;
    char buf[BUFFLEN] = {0};
    int read_size;
    static uint64_t next_update;
    uint64_t now = mstime();
    int timeout = 0;
    int abort = 0;
    char temp_char;
    char * s_key = malloc(33);
    short *c_key_validated = malloc(2);
    char * c_serial = malloc(30);
    int32_t *c_version = 0;


    *c_key_validated = 0;
    next_update = now + 1000;
    signal(SIGCHLD, SIG_IGN);

    pthread_mutex_lock(&m_client_count);
    client_count++;
    pthread_mutex_unlock(&m_client_count);

    airnav_log_level(9, "[client_socket] Socket value: %d\n", sock);

    // Initial com
    while (!abort) {

        read_size = recv(sock, &temp_char, 1, MSG_PEEK);

        if (read_size > 0) { // The size os initial com packet is 41            

            if (buf_idx < BUFFLEN && (read_size = recv(sock, &temp_char, 1, 0) > 0)) {

                if (temp_char == '\n') {                    
                    procPacket(buf, socket_desc, s_key, (int32_t*) c_version, c_key_validated, c_serial); // Proccess the package                                        
                    memset(&buf[0], 0, sizeof (buf)); // Clear the buffer
                    buf_idx = 0;
                    temp_char = 0;
                } else {
                    buf[buf_idx] = temp_char;
                    buf_idx++;
                    temp_char = 0;
                }

                timeout = 0;
            } else {
                airnav_log_level(6, "[client_socket] Buffer Cheio!\n");
            }

        } else {

            usleep(10000);
            now = mstime();
            if (now >= next_update) {
                next_update = now + 1000;
                timeout++;
                airnav_log_level(6, "[Key: %s] Timeout...%d\n", s_key, timeout);
                //airnav_log_level(9,"[client_socket] Socket value (timeout): %d\n",sock);
            }

            if (timeout >= CLIENT_TIMEOUT) {
                abort = 1;
            }

        }


    }

    pthread_mutex_lock(&m_client_count);
    client_count--;
    pthread_mutex_unlock(&m_client_count);
    airnav_log("Client disconnected\n");

    return 0;
}

在procPacket的最后,这就是我所做的:

pthread_mutex_lock(&m_data_packet_count);
        data_packet_count++;
        pthread_mutex_unlock(&m_data_packet_count);

        // Only save packet if key is validated
        if (*key_validated == 1) {

            // For every server listening
            struct s_packets *s1;            
            for (int sc = 0; sc < MAX_SERVERS; sc++) {

                // Is this server active?
                if (serverList[sc].active == 1) { // Yes, then queue msg
                    airnav_log_level(7, "Servidor %d ativo! Adicionando msg...\n", sc);
                    s1 = malloc(sizeof (struct s_packets));
                    strcpy(s1->callsign, p_callsign);
                    //strcpy(s1->c_key, c_key);                    
                    s1->next = serverList[sc].packets;
                    serverList[sc].packets = s1;

                } else {
                    airnav_log_level(7, "Servidor %d offline!\n", sc);
                }


            }            


        }

在服务器句柄功能上,我的connection_handle差不多,但有点不同:) 我所做的是: 1)锁定服务器列表的互斥锁; 2)将serverList包的指针复制到本地指针 3)清除serverList包的指针 4)unclock mutex 5)将本地指针的数据包发送到此句柄中连接的服务器。

这样工作正常,但是如果我非常快地连接/断开3~4服务器,我的程序简单就会崩溃,并且在“procPackets&#39;”的malloc中出错!

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff3192700 (LWP 23449)]
_int_malloc (av=av@entry=0x7fffe4000020, bytes=bytes@entry=72) at malloc.c:3367
3367        while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
(gdb) bt
#0  _int_malloc (av=av@entry=0x7fffe4000020, bytes=bytes@entry=72) at malloc.c:3367
#1  0x00007ffff6567fbc in __GI___libc_malloc (bytes=72) at malloc.c:2893
#2  0x00000000004033b8 in procPacket (packet=packet@entry=0x7ffff3190de0 "", socket_=socket_@entry=0x7fffec0008c0, c_key=c_key@entry=0x7fffe40008c0 "5c1d413807f961f5e331d03be5201c0e",
    c_version=c_version@entry=0x0, key_validated=key_validated@entry=0x7fffe40008f0, sn=sn@entry=0x7fffe4000910 "") at rbrpiserver.c:937
#3  0x0000000000403676 in connection_handler (socket_desc=0x7fffec0008c0) at rbrpiserver.c:668
#4  0x00007ffff7bc8dc5 in start_thread (arg=0x7ffff3192700) at pthread_create.c:308
#5  0x00007ffff65df73d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:113
我错过了什么? :( 我无法看到这里可能出现的问题。 这是来自server_handle的代码的一部分:

// Let's clear the incoming buffer, if exists
        *read_size = recv(*sock, temp_char, 4096, MSG_DONTWAIT);
        airnav_log_level(5, "READ-SIZE for slot %d: %d, sock value: %d, sock address: %p\n", *slot, *read_size,*sock,sock);
        if (*read_size != 0) { // Connection still active
            *timeout = 0;

            *cou = 0;
            pthread_mutex_lock(&m_server_list);
            local_list = serverList[*slot].packets;
            serverList[*slot].packets = NULL;
            //pthread_mutex_unlock(&m_server_list);

            p_tmp1 = local_list;
            while (p_tmp1 != NULL) {

                if (*lost == 0) {
                    if (sendServerSocketPacket(socket_desc, p_tmp1) == -1) {
                        *lost = 1;
                        *abort = 1;
                    }
                } else {
                    *abort = 1;
                }
                p_tmp2 = p_tmp1;
                p_tmp1 = p_tmp1->next;
                free(p_tmp2);
                p_tmp2 = NULL;
            }
            pthread_mutex_unlock(&m_server_list);

            if (p_tmp1 != NULL) {
                free(p_tmp1);
                p_tmp1 = NULL;
            }
            local_list = NULL;
            sleep(SERVER_SOCKET_SEND_TIME); // Replace with function that send data to the client
            *now = mstime();
        } else {

            sleep(1);
            *now = mstime();
            if (*now >= *next_update) {
                *next_update = *now + 1000;
                *timeout = *timeout + 1;
                airnav_log_level(5, "Timeout [server %d]...%d\n", *slot, *timeout);
            }

            if (*timeout >= SERVER_TIMEOUT) {
                *abort = 1;
                airnav_log_level(5, "[server %d] Timeout esgotado! Saindo...\n", *slot);
            }

        }

更新 顺便说一句,我发现了这个问题。在server_handle中,在连接/功能结束时,我正在清除serverlist socket的套接字......然后,当一个新的服务器 - 客户端&#39;套接字连接,我尝试重新使用这个列表项,套接字不再创建!当客户端连接时,我没有在serverList.socket中为这个套接字设置malloc空间,因为它应该已经被分配了......但是我是免费的(?)&#39;这个套接字当&#39; server-client&#39;断开....哑巴!唯一奇怪的是错误与此功能无关。我已经从server_handle中删除了清洁代码,现在它已经完美运行了!

0 个答案:

没有答案