csocketsudpposix-select

C socket - not all socket receive in select()


i've a problem wiht my multi-threads project: i create some threads, these must send and receive udp messages with each other, so each thread is listening on multiple sockets with an select(). The problem is: only last socket inserted in a fd_set variable, receive messages. I don't konw why

this is code:

initial part of thread:

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;
        }

secondo part of thread:

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(...);

                        }
                    }
                }
            }
        }
    }                                                       

}       

anyone can help me?

The entire project is here: https://github.com/bonfi/SpanningTreeUDP

(sorry for my english, i'm italian, the project is commented in italian)


Solution

  • I believe there are is at least one if not two issues. The first one is in the second part, in the recvfrom function, you are using socketfd but not setting it to the socket from which you want to receive data. The variable socketfd contains the last socket you created from the initial code. I suspect that is why you are only getting data from one thread which was the last socket created.

    The other item which I don't quite understand is the loop after the if statement with teh FD_ISSET in the second part. I'm not sure why you are looping with x and then setting p or why you are doing 4 times.

    I would propose the code in the second part should look like the follow starting at the FD_ISSET if statement.

            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(...);
    
                }
            }
    

    I removed the for loop with the x variable and I am using p to index the structure to set the socketfd for receiving data based on if the FD_ISSET returns true. That way you are setting the socketfd variable based on the file descriptor if it is set.