我试图在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中删除了清洁代码,现在它已经完美运行了!