我一直在使用unix套接字和pthreads在C中编写一个小型多线程TCP服务器,但我遇到了accept()问题。它会挂起第二个请求,只有在先前的线程退出时才会解锁。
以下是我设置服务器套接字的方法。
int server_start(server_t *server, int port) {
int fd;
struct sockaddr_in server_addr;
// Socket file descriptor.
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
perror("socket failed");
return 1;
}
// Socket address.
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
// Bind.
if (bind(fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
perror("bind failed");
return 1;
}
server->fd = fd;
listen(server->fd, server->clients_len);
pthread_create(&(server->thread), NULL, thread_entry_server, server);
return 0;
}
这是我的add_client代码。它为客户端生成一个单独的线程。
client_t *server_add_client(server_t *server) {
int iter,
fd,
status;
client_t *client;
printf("before\n");
fd = accept(server->fd, NULL, 0);
printf("after\n");
if (fd == -1) {
perror("accept");
return NULL; // Connection failed.
}
// Find an empty spot.
client = server->get_empty_spot();
client->fd = fd;
// Start the new thread.
status = pthread_create(
&(client->thread),
NULL,
thread_entry_client,
client
);
if (status != 0) {
perror("pthread_create");
close(client->fd);
return NULL;
}
client->active = 1;
return client;
}
这是我的客户端线程的入口函数:
void *thread_entry_client(void *void_client) {
client_t *client = void_client;
int len;
while (1) {
len = recv(client->fd, client->recv_buffer, RECV_BUFFER_LEN, 0);
if (len < 0) {
perror("recv");
client->active = 0;
close(client->fd);
return NULL;
}
if (len == 0) { // Client disconnected.
client->active = 0;
close(client->fd);
printf("disconnect\n");
return NULL;
}
if (len > 0) {
//printf("%s\n", client->recv_buffer);
printf("msg\n");
}
}
return NULL;
}
所以我正在做的测试是建立两个连接。第一个连接通过并正常工作,但第二个连接没有 - 而是线程挂起在accept()上。我从printfs(我已经离开那里)知道了这一点,并且我知道在第一个客户端断开连接后,accept()解除阻塞。我也知道我的代码没有关闭服务器套接字文件描述符或更改它。
有关调试的建议吗?我无法理解。
编辑:这是thread_entry_server。
void *thread_entry_server(void *void_server) {
server_t *server = void_server;
client_t *client;
while (1) {
client = server_add_client(server);
if (client == NULL) // Server is full or connection failed.
continue;
}
return NULL;
}
答案 0 :(得分:0)
这是因为accept()
将阻止(除非另有配置),直到客户端连接可用。
请参阅提及的Documentation -
如果侦听队列没有连接请求且O_NONBLOCK是 没有设置套接字的文件描述符,accept()将阻塞 直到存在连接。如果listen()队列为空 连接请求和O_NONBLOCK在文件描述符上设置 套接字,accept()将失败并将errno设置为[EAGAIN]或 [EWOULDBLOCK]。
此外,server->get_empty_spot();
应该始终返回新的client
个实例,否则就意味着您将同一个client->thread
传递给pthread_create
。
我通常更喜欢自己创建新帖子,比如 -
**pthread_t newListner;**
ThreadArgs thread_args;
thread_args.client_socket = client_socket;
int rc;
if ((rc = pthread_create(&newListner, NULL, startListener, &thread_args)))
{ .. }
试一试。
答案 1 :(得分:0)
我正在使用javascript websocket进行测试,但我没有进行任何握手,因此它没有完成连接。使用telnet进行测试。