我的多线程项目有一个问题:我创建了一些线程,这些线程必须相互发送和接收 udp 消息,因此每个线程都在使用 select() 监听多个套接字。问题是:只有在最后一个socket中插入一个fd_set变量,才能接收消息。我不知道为什么
这是代码:
线程的初始部分:
int fdmax;
fd_set read_fd_set, service_fd_set;
/* allocate memory for receive msg */
msg=malloc(sizeof(char)*(SIZEBUF));
FD_ZERO(&read_fd_set);
FD_ZERO(&service_fd_set);
fdmax=0;
if (param->n_port != 0){
for (x=0; x<(param->n_port); x++){
/* take the port from array */
local_port_number = param->l_port_in[x];
/* create socket udp and bind on localhost */
socketfd=create_socket(local_port_number);
/* save socket_fd in my data struct */
param->sock_fd_local[x]=socketfd;
/* add socket in fd_set */
FD_SET(socketfd,&service_fd_set);
if (socketfd > (fdmax-1)){
fdmax=socketfd + 1;
}
线程的第二部分:
for(;;){
read_fd_set=service_fd_set;
ris=select(fdmax,&read_fd_set,NULL,NULL,NULL);
if(ris<0){
if (errno!=EINTR){
printf(_KRED "Error in select: errno different from EINTR \n" _KNRM);
}
}
if (ris>0){
for(p=0; p<fdmax; p++){
if((FD_ISSET(p,&read_fd_set))!=0){
for( x=1; x<=5; x++){
if( p == param->sock_fd_local[x]){
/* setup datagram to receive */
memset(&From, 0, sizeof(From));
Fromlen=sizeof(struct sockaddr_in);
/* RECVFROM */
msglen = recvfrom ( p, msg, (int)SIZEBUF, 0, (struct sockaddr*)&From, &Fromlen);
if (msglen<0){
...
}else{
sprintf((char*)string_remote_ip_address,"%s",inet_ntoa(From.sin_addr));
remote_port_number = ntohs(From.sin_port);
print_msg(...);
}
}
}
}
}
}
}
谁能帮帮我?
整个项目在这里:https://github.com/bonfi/SpanningTreeUDP
(抱歉我的英语不好,我是意大利人,该项目用意大利语评论)
最佳答案
我相信至少有一个(如果不是两个)问题。第一个是在第二部分中,在 recvfrom 函数中,您正在使用 socketfd 但没有将其设置为要从中接收数据的套接字。变量 socketfd 包含您从初始代码创建的最后一个套接字。我怀疑这就是为什么您只能从一个线程获取数据,该线程是最后创建的套接字。
另一个我不太明白的项目是第二部分中带有 teh FD_ISSET 的 if 语句之后的循环。我不确定你为什么要循环 x 然后设置 p 或者你为什么要这样做 4 次。
我建议第二部分的代码应该如下所示,从 FD_ISSET if 语句开始。
if((FD_ISSET(p,&read_fd_set))!=0){
socketfd == param->sock_fd_local[p]){
/* setup datagram to receive */
memset(&From, 0, sizeof(From));
Fromlen=sizeof(struct sockaddr_in);
/* RECVFROM */
msglen = recvfrom ( socketfd, msg, (int)SIZEBUF, 0, (struct sockaddr*)&From, &Fromlen);
if (msglen<0){
...
}else{
sprintf((char*)string_remote_ip_address,"%s",inet_ntoa(From.sin_addr));
remote_port_number = ntohs(From.sin_port);
print_msg(...);
}
}
我删除了带有 x 变量的 for 循环,我正在使用 p 来索引结构,以根据 FD_ISSET 是否返回 true 来设置用于接收数据的 socketfd。这样你就可以根据文件描述符设置 socketfd 变量(如果已设置)。
关于C 套接字 - 并非所有套接字都在 select() 中接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24061011/