c - 为什么 select() 对收到的消息没有反应?

标签 c sockets network-programming

当我收到来自任何特定主机的返回数据时,我尝试中止向特定主机发送 UDP 数据。

到目前为止,我尝试的是在发送数据的其他函数中创建一个线程。

线程应该在最多 100 秒的时间内检查套接字描述符上的传入数据。

但是 select() 函数仅等待超时,并且在接收数据时不响应。套接字已经在调用函数中创建,这里我只传递文件描述符。

这也是 Beej 网络编程指南中修改后的代码片段。

void *bot_listen(void *arg){

    printf("Thread starting\n");
    size_socks *sock_size=(size_socks*)arg;
    int  n, rv;
    fd_set readfds;
    struct timeval tv;

    thr_running=1;

    FD_ZERO(&readfds);

    for(int i=0;i<sock_size->size;i++) {
        FD_SET(sock_size->sockets[i], &readfds);
    }

    n = sock_size->size + 1;

    tv.tv_usec = 0;
    tv.tv_sec = 100;
    rv = select(n, &readfds, NULL, NULL, &tv);
    if (rv == -1) {
        perror("select"); // error occurred in select()
    } else if (rv == 0) {
        printf("Timeout occurred!  No data after 100 seconds.\n");
    } else {
        bot_recv_message=1;
    }
    thr_running=0;
}
void send_dgrams(int num_ip, struct message ip_port_pairs, char *message){
        struct addrinfo hints, *res;
        struct sockaddr_in *dest;
        char udp_ip[INET_ADDRSTRLEN];
        char str[INET6_ADDRSTRLEN];
        char udp_port[22];
        char *p;
        int *sockfd, time_elapsed=0;
        size_socks ss;

        printf("Message, beginning of send_dgrams: %s\n", message);
        pthread_t listen_thread;

        sockfd = (int*)malloc(sizeof(int)*num_ip);
        dest = malloc(sizeof(struct sockaddr_in)*num_ip);
        p=&(ip_port_pairs.command);
        p++;

        for(int i =0; i<num_ip;i++) {

            memset(&hints, 0, sizeof(hints));

            hints.ai_family = AF_UNSPEC;
            hints.ai_socktype = SOCK_DGRAM;
            strcpy(udp_ip, p);
            p+=INET_ADDRSTRLEN;
            strcpy(udp_port,p);
            p+=22;

            getaddrinfo(udp_ip, udp_port, &hints, &res);
            sockfd[i] = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

            dest[i].sin_family = res->ai_family;
            dest[i].sin_port = ((struct sockaddr_in *) res->ai_addr)->sin_port;
            dest[i].sin_addr = ((struct sockaddr_in *) res->ai_addr)->sin_addr;
            memset(dest[i].sin_zero, '\0', sizeof(dest[i].sin_zero));
        }

        ss.size=num_ip;
        ss.sockets=sockfd;
        pthread_create(&listen_thread, NULL, bot_listen, (void*)&ss);
        while(bot_recv_message==0 && time_elapsed<100) {
            for (int i = 0; i < num_ip; i++) {
                printf("Sending this message: %s to socket %d\n", message, sockfd[i]);
                inet_ntop(AF_INET, &(dest[i].sin_addr), str, INET_ADDRSTRLEN);
                printf("Sending to this address: %s\n", str);
                printf("Sending to this port: %d\n", ntohs(dest[i].sin_port));
                printf("Did bot receive message? :%d\n", bot_recv_message);
                sendto(sockfd[i], message, strlen(message) + 1, 0, (struct sockaddr *) &dest[i], sizeof(dest[i]));
            }
            sleep(1);
            time_elapsed+=1;
        }

        for(int i=0;i<num_ip;i++){
            close(sockfd[i]);
        }
        bot_recv_message=0;
    }

最佳答案

这可能是问题所在:

n = sock_size->size + 1;
...
rv = select(n, &readfds, NULL, NULL, &tv);

select() 第一个参数的值不够大。

select() 的手册页对第一个参数进行了以下说明:

nfds should be set to the highest-numbered file descriptor in any of the three sets, plus 1. The indicated file descriptors in each set are checked, up to this limit (but see BUGS).

所以尝试这样的事情:

int max_fd = -1;

for(int i=0;i<sock_size->size;i++) {
    FD_SET(sock_size->sockets[i], &readfds);
    if (sock_size->sockets[i] > max_fd)
         max_fd = sock_size->sockets[i]; 
}
...
rv = select(max_fd + 1, &readfds, NULL, NULL, &tv);

关于c - 为什么 select() 对收到的消息没有反应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56111453/

相关文章:

c - strlen() 如何计算当前函数中未定义的字符串的长度?

c - 在 C 的 switch 语句中重新声明变量

c - 我如何设置套接字来执行 "send/receive"或 "receive/send"

linux - 使用 MSG_NONBLOCK 和 MSG_WAITALL 接收

Android 通过 WiFi 路由下行数据,通过移动网络路由上行数据

在 C 中计算 APY 公式

c - strncpy导致段错误

java - BluetoothServerSocket 不从 accept() 返回

java - Java中的多线程服务器程序

c - 将数据报发送到无法到达的目的地时,sendto() 对于 IPv4 和 IPv6 有不同的行为