使用select处理多个客户端请求会导致循环重新启动
这是我到目前为止的代码,我基本上有一个fd使用select处理多个客户端请求会导致循环重新启动,c,sockets,network-programming,C,Sockets,Network Programming,这是我到目前为止的代码,我基本上有一个fdsock\u comm,它是监听套接字,然后将建立并添加多个客户端套接字连接。我需要能够接受新的连接,但也能够接收现有的连接,因此我使用select。我在尝试遍历while循环意外重新启动的现有连接时遇到了一个问题 int n = sock_comm+1; int max_sock; while (1) { max_sock = n; printf("sock_comm: %d\n", sock_comm); // Clear
sock\u comm
,它是监听套接字,然后将建立并添加多个客户端套接字连接。我需要能够接受新的连接,但也能够接收现有的连接,因此我使用select
。我在尝试遍历while循环意外重新启动的现有连接时遇到了一个问题
int n = sock_comm+1;
int max_sock;
while (1) {
max_sock = n;
printf("sock_comm: %d\n", sock_comm);
// Clear the fd_set and add back connections
FD_ZERO(&readfds);
for (int i=sock_comm; i < max_sock; i++) {
FD_SET(i, &readfds);
}
select(n, &readfds, NULL, NULL, NULL);
printf("max socket: %d\n", max_sock);
fd = sock_comm;
// Iterate through each connection
while (fd < max_sock) {
printf("fd: %d\n", fd);
printf("sock_comm2: %d\n", sock_comm);
// If activity on current connection
if (FD_ISSET(fd, &readfds)) {
printf("Connection on %d\n", fd);
// If connection on listener, accept
if (fd == sock_comm) {
if ((new_s = accept(sock_comm, (struct sockaddr *)&client_addr, &len)) < 1) {
perror("tcpserver: accept");
exit(1);
}
n++;
client_info.sockid = new_s;
// Join handler thread
pthread_create(&threads[0],NULL,join_handler,&client_info);
pthread_join(threads[0],&exit_value);
printf("sock_comm3: %d\n", sock_comm);
} else {
// Create and join thread for receiving data
}
}
fd++;
printf("sock_comm4: %d\n", sock_comm);
}
}
然后,选择过程再次开始。但现在发生的是:
sock_comm: 3
max socket: 4
fd: 3
sock_comm2: 3
Connection on 3
sock_comm3: 3
sock_comm4: 3
fd: 1
sock_comm2: 3
sock_comm4: 3
fd: 2
sock_comm2: 3
sock_comm4: 3
fd: 3
sock_comm2: 3
Connection on 3
正如您所看到的,while(fd
循环正在重置,不知何故从1开始,但是fd
永远不会降到3以下。我不知道我的代码出了什么问题,这与在循环中使用select
有关吗?我以前从未使用过,但它会导致奇怪的行为。当没有可接受的内容时,它会陷入接受状态
联接处理程序:
void *join_handler(struct global_table *rec) {
int newsock;
struct packet packet_reg;
newsock = rec->sockid;
for (int i=0; i < REQUEST_NO; i++) {
if (recv(newsock, &packet_reg, sizeof(packet_reg), 0) < 1) {
printf("Could not receive RG-%d\n", i+1);
exit(1);
} else {
printf("Registered received: %s\n",packet_reg.data);
}
}
// add to table
pthread_mutex_lock(&my_mutex);
counter++;
record[counter].sockid = newsock;
pthread_mutex_unlock(&my_mutex);
// send response acknowledging registration
packet_reg.type = htons(221);
sprintf(packet_reg.data, "%d", newsock);
if(send(newsock, &packet_reg, sizeof(packet_reg), 0) < 1) {
printf("ACK send failed\n");
exit(1);
}
pthread_exit(NULL);
}
void*join\u处理程序(结构全局表*rec){
国际新闻股;
结构数据包\u reg;
newsock=rec->sockid;
对于(int i=0;i
在这样的循环中调用select()
是正常的。我在你发布的代码中没有看到任何东西可以设置fd
小于sock\u comm
。可能在覆盖变量的另一个线程中有错误的代码?如果将变量fd
设置为本地,而(1)
循环,会发生什么情况?另一个线程只处理本地变量,并使用新套接字发送确认。将fd
本地设置为,而(1)
则会明显改变行为。现在我在新的fd
上的recv
中得到了一个神秘的结果,当没有从客户端发送数据包时,它是通过accept创建的。readfds
中只有sock\u comm
。因此,您的recv
将永远不会执行[并且您不想在那里使用recv
]。您不显示thread funct,但希望让main
doaccept
并将结果传递给pthread\u create
,然后让函数dorecv
。此外,您还需要比立即pthread\u连接更好的方法。您可能希望线程func独立运行,以便获得并行性。请注意,如果您需要传递client\u info
,则必须malloc
one[线程func执行free
],否则您将获得竞态条件。或者,只要使用(void*)new\u s
我不太清楚,如果要为每个客户端创建线程,为什么要使用select()
。线程的全部目的是简化多路复用。
void *join_handler(struct global_table *rec) {
int newsock;
struct packet packet_reg;
newsock = rec->sockid;
for (int i=0; i < REQUEST_NO; i++) {
if (recv(newsock, &packet_reg, sizeof(packet_reg), 0) < 1) {
printf("Could not receive RG-%d\n", i+1);
exit(1);
} else {
printf("Registered received: %s\n",packet_reg.data);
}
}
// add to table
pthread_mutex_lock(&my_mutex);
counter++;
record[counter].sockid = newsock;
pthread_mutex_unlock(&my_mutex);
// send response acknowledging registration
packet_reg.type = htons(221);
sprintf(packet_reg.data, "%d", newsock);
if(send(newsock, &packet_reg, sizeof(packet_reg), 0) < 1) {
printf("ACK send failed\n");
exit(1);
}
pthread_exit(NULL);
}