-1

I'm implementing server-client between 2 computers, the idea is to read inputs from connected slave to PC3 and to send it to PC4 and also the way back (inputs from connected slave P4 and send it to PC3).

the side of server:

client:
static void FSoEThread()
{
   struct timeval time1;

   uint8_t  pdu_in_local[sizeof(pdu_in)];
   uint8_t  pdu_out_local[sizeof(pdu_out)];

   uint8_t  pdu_in_tmp[sizeof(pdu_in)];
   uint8_t  pdu_out_tmp[sizeof(pdu_out)];

   FILE *fp;
   fp = fopen("Log.txt", "w");//opening file.
   SerialPort sp(MODEMDEVICE);
   
    int socket_desc;
    struct sockaddr_in server_addr;
    unsigned int  server_message[255], client_message[255];
    socklen_t server_struct_length = sizeof(server_addr);
;

   printf("Thread_quit\n");

     while(!thread_quit){

    
        std::vector<uint8_t> uart_in(10);
        sp.Read(uart_in);

       if(1){
        switch(ecatGetMasterState())
        {
        default:

            break;
        case _UNKNOWN:
        case _INIT:
        case _PREOP:
        case _SAFEOP:
            break;
        case eEcatState_OP:
        {

            {
                uint8_t buf[sizeof(pdu_in)]; // In data comes from Slave
                if(uart_in.size() == 10){
                    PD_mutex.lock();
                    memcpy(pdu_out,&uart_in.data()[4],sizeof(pdu_out));//out data coming from Master to the Slave
                    memcpy(pdu_out_local,&uart_in.data()[4],sizeof(pdu_out));

                    memcpy(buf,pdu_in,sizeof(pdu_in));
                    memcpy(pdu_in_local,pdu_in,sizeof(pdu_in));

                    PD_mutex.unlock();
                        printf("\n");
                    sp.Write(buf,sizeof(pdu_in));
        }
        }
            

            gettimeofday(&time1,NULL);

            if(memcmp(pdu_in_tmp,pdu_in_local,sizeof(pdu_in)) != 0){
                memcpy(pdu_in_tmp,pdu_in_local,sizeof(pdu_in));

                fprintf(fp,"[%05d.%06d]in  %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_in_tmp[0],
                        (unsigned int)pdu_in_tmp[1],
                        (unsigned int)pdu_in_tmp[2],
                        (unsigned int)pdu_in_tmp[3],
                        (unsigned int)pdu_in_tmp[4],
                    (unsigned int)pdu_in_tmp[5]
                );
            unsigned int *PDU_UDP_IN = (unsigned int*)pdu_in_tmp;  
            // Create socket:
            socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(socket_desc < 0){
            printf("Error while creating socket\n");
            exit(1);
            }

            // Clean buffers:
            memset(server_message, 0, sizeof(server_message));
            memset(client_message, 0, sizeof(client_message));


            // Set port and IP:
            server_addr.sin_family = AF_INET;
            server_addr.sin_port = htons(2000);
            server_addr.sin_addr.s_addr = inet_addr("10.100.20.54");

            printf("sending\n");
            // Send the message to server:
            if(sendto(socket_desc, PDU_UDP_IN, sizeof(PDU_UDP_IN), 0,
             (struct sockaddr*)&server_addr, server_struct_length) < 0){
            printf("Unable to send message\n");
            exit(1);
            }

            printf("sendto: msg send to IPC4 :\t%x\n",*PDU_UDP_IN);    

                socklen_t server_struct_length = sizeof(server_addr);
            
                
            //recvfrom(socket_desc, server_message, sizeof(server_message), 0,(struct sockaddr*)&server_addr, &server_struct_length);
            //if(int errn_ = recvfrom(socket_desc, server_message, sizeof(server_message), 0,(struct sockaddr*)&server_addr, &server_struct_length) < 0){
            //printf("Error while receiving server's msg\n");
            //printf("n=%d, Errno%d\n",errn_,errno);
            //exit(1);
            //}
            printf("Recved\n");
            printf("MSG from IPC4:\t%x\n",*server_message);    
            close(socket_desc);
            }

            if(memcmp(pdu_out_tmp,pdu_out_local,sizeof(pdu_out)) != 0){
                memcpy(pdu_out_tmp,pdu_out_local,sizeof(pdu_out));
    
                fprintf(fp,"[%05d.%06d]out %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_out_tmp[0],
                        (unsigned int)pdu_out_tmp[1],
                        (unsigned int)pdu_out_tmp[2],
                        (unsigned int)pdu_out_tmp[3],
                        (unsigned int)pdu_out_tmp[4],
                        (unsigned int)pdu_out_tmp[5]
                );
    }


        }
    }
        }
     }


   pthread_exit(NULL);
}


This side if working good... it can send and receive ...

now the client side where the problem happens.... say i comment/delete recvfrom in this side of client(PC3)..all works fine (also server side recvfrom and sendto works and i get data and can send data) when trying to receive (using the recvfrom function again in Client) data are exchanged 4 times and then both client and server do nothing anymore -> I'm going in deadlock and both are BLOCKED IN RECVFROM


static void FSoEThread()
{
   struct timeval time1;

   uint8_t  pdu_in_local[sizeof(pdu_in)];
   uint8_t  pdu_out_local[sizeof(pdu_out)];

   uint8_t  pdu_in_tmp[sizeof(pdu_in)];
   uint8_t  pdu_out_tmp[sizeof(pdu_out)];



    int socket_desc;
    struct sockaddr_in server_addr, client_addr;
    unsigned int server_message[255], client_message[255];
            socklen_t client_struct_length = sizeof(client_addr);


       // Clean buffers:
       memset(server_message, '\0', sizeof(server_message));
       memset(client_message, '\0', sizeof(client_message));
       FILE *fp;
       fp = fopen("Llog.txt", "w");//opening file.
       long save_fd;
    SerialPort sp(MODEMDEVICE);


   printf("thread_quit\n");

           while(!thread_quit){

        std::vector<uint8_t> uart_in(10);
        sp.Read(uart_in);

       if(1){
        switch(ecatGetMasterState())
        {
        default:
            break;
        case _UNKNOWN:
        case _INIT:
        case _PREOP:
        case _SAFEOP:
            break;
        case eEcatState_OP:    
        {
            {
                uint8_t buf[sizeof(pdu_in)];
                if(uart_in.size() == 10){
                    PD_mutex.lock();
                    memcpy(pdu_out,&uart_in.data()[4],sizeof(pdu_out));
                    memcpy(pdu_out_local,&uart_in.data()[4],sizeof(pdu_out));

                    memcpy(buf,pdu_in,sizeof(pdu_in));
                    memcpy(pdu_in_local,pdu_in,sizeof(pdu_in));
                    PD_mutex.unlock();

                    sp.Write(buf,sizeof(pdu_in));

                }
            }

            gettimeofday(&time1,NULL);

            if(memcmp(pdu_in_tmp,pdu_in_local,sizeof(pdu_in)) != 0){
                memcpy(pdu_in_tmp,pdu_in_local,sizeof(pdu_in));

                fprintf(fp,"[%05d.%06d]in  %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_in_tmp[0],
                        (unsigned int)pdu_in_tmp[1],
                        (unsigned int)pdu_in_tmp[2],
                        (unsigned int)pdu_in_tmp[3],
                        (unsigned int)pdu_in_tmp[4],
                        (unsigned int)pdu_in_tmp[5]
                );
            
            unsigned int * PDU_UDP_IN = (unsigned int*)pdu_in_tmp;
            printf("in \t%X\n",*PDU_UDP_IN);
                           // Create UDP socket:
            socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
            if(socket_desc < 0){
            printf("Error while creating socket\n");
            exit(1);
            }
            // Set port and IP:
            server_addr.sin_family = AF_INET;
            server_addr.sin_port = htons(2000);
            server_addr.sin_addr.s_addr = inet_addr("10.100.20.54");

            // Bind to the set port and IP:
            if(bind(socket_desc, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0){

            exit(1);
            }

            //printf("Listening for incoming messages...\n\n");
            // Receive client's message:
            
            printf("Recving\n");
            if (recvfrom(socket_desc, client_message, sizeof(client_message), 0,(struct sockaddr*)&client_addr, &client_struct_length) < 0){
            //printf("Couldn't receive\n");
            //continue;
            }
            printf("Received\n");
            //     inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));

            printf("msg from IPC3:\t%x\n", *client_message);

            // Respond to client:
            
            printf(" sending\n");
            // strcpy(server_message, client_message);
            socklen_t client_struct_length = sizeof(client_addr);
            if (sendto(socket_desc, PDU_UDP_IN, sizeof(PDU_UDP_IN), 0,
             (struct sockaddr*)&client_addr, client_struct_length) < 0){
            printf("Can't send\n");
            exit(EXIT_FAILURE);
            }
            printf(" sent\n");
            // Close the socket:
            close(socket_desc);
            }

            if(memcmp(pdu_out_tmp,pdu_out_local,sizeof(pdu_out)) != 0){
                memcpy(pdu_out_tmp,pdu_out_local,sizeof(pdu_out));

                fprintf(fp,"[%05d.%06d]out %02x %02x %02x %02x %02x %02x\n",time1.tv_sec,time1.tv_usec,
                        (unsigned int)pdu_out_tmp[0],
                        (unsigned int)pdu_out_tmp[1],
                        (unsigned int)pdu_out_tmp[2],
                        (unsigned int)pdu_out_tmp[3],
                        (unsigned int)pdu_out_tmp[4],
                        (unsigned int)pdu_out_tmp[5]
                );

            }

        }
        }
        }
     }

   pthread_exit(NULL);
}





my questions:

1-Am i doing something wrong here?

2-is there any work-around to overcome this problem in easier way? i was reading about select but i dont know it it works when im using 2 PCs with different Threads

3- im trying since days with flags like MSG_DONTWAIT , tried to use setsockopt() ...

4- is there is a way to really debug this situation?

I would be really thankful for your answers

The programm is really big...those are the parts for UDP implmentaion... in is written in C/C++ and all other sections works perfect, the problem is only to know how to make UDP stop blocking at recvfrom

Adriaan
  • 17,741
  • 7
  • 42
  • 75
  • I think [this post](https://stackoverflow.com/questions/13317532/receiving-a-part-of-packet-via-recvfrom-udp) may answer your questions... – ryyker Jun 22 '22 at 13:53
  • [This post](https://stackoverflow.com/a/14818347/645128) is also relevant. – ryyker Jun 22 '22 at 13:55
  • Are these two `Thread()` functions supposed to be the entry functions for pthreads threads? If so then their signatures are wrong. – John Bollinger Jun 22 '22 at 14:03
  • @JohnBollinger - That link is also in the first comment. Feel free to use it should you decide to close :) – ryyker Jun 22 '22 at 14:08
  • 1
    @ryyker, I doubt that the function signature issue is the main problem here. But I suspect that we may not have sufficient information to determine what the main problem actually is. – John Bollinger Jun 22 '22 at 14:12
  • 1
    FWIW - the [select()](https://www.ibm.com/docs/en/i/7.1?topic=designs-example-nonblocking-io-select) statement allows a process _"to wait for an event to occur and to wake up the process when the event occurs"_, and for example to return a value for the socket descriptor that is ready to be processed. I have found it to be a useful component piece to help govern multiple sockets. – ryyker Jun 22 '22 at 14:12
  • The code presented does not afford a clear way in which "data are exchanged 4 times" could happen. It's also not clear to me what, exactly, "if recvfrom exists" means in this context. Please present a *bona fide* [mre] that demonstrates the issue. That should both *include* all the code necessary to reproduce the problem, and *exclude* all code that is not necessary to reproduce it. – John Bollinger Jun 22 '22 at 14:17
  • okay i will add a bona fide and i think its ganna be easier to understnad... by "if recvfrom exists" i mean : *if i delete recvfrom in client side -> program from server side receive and send data. *if i add the recvfrom function again... program send and receive 4 times and stop to do anything even-though slaves are running – Hilal Abu-Saleh Jun 22 '22 at 15:31
  • 1
    Please don't make more work for other people by vandalizing your posts. By posting on the Stack Exchange network, you've granted a non-revocable right, under the [CC BY-SA 4.0 license](https://creativecommons.org/licenses/by-sa/4.0/), for Stack Exchange to distribute that content (i.e. regardless of your future choices). By Stack Exchange policy, the non-vandalized version of the post is the one which is distributed. Thus, any vandalism will be reverted. If you want to know more about deleting a post please see: [How does deleting work?](https://meta.stackexchange.com/q/5221) – Adriaan Sep 16 '22 at 07:57

1 Answers1

1
  1. Am i doing something wrong here?

You seem to have a bunch of race conditions and misconceptions about UDP.

If the server sends a datagram to the client, when the client doesn't have the socket bound - the datagram is just lost. It isn't queued up until later. You have the same problem on the reverse path.

If both server & client sockets are kept open, at least datagrams will be queued until their buffers fill up. This gives you a pretty good chance to read a message before it is lost for ever.

Even with this though, blocking recvfrom is certainly a mistake here. A datagram could simply be lost due to network congestion, and hanging indefinitely is not a good response to that.

  1. Is there any workaround to overcome this problem in easier way? i was reading about select but i dont know it it works when im using 2 PCs with different Threads

If you don't know enough to handle this with non-blocking UDP (or quite reasonably don't want to spend the time required), just use TCP, and remember to set TCP_NODELAY.

  1. I'm trying since days with flags like MSG_DONTWAIT , tried to use setsockopt()

Try to find a second hand copy of TCP/IP Illustrated Vol.1, if possible the older Stevens version (it's missing the newer updates, but covers the basics just fine and the sequence diagrams are better IIRC). Figuring this stuff by trial and error is painful.

  1. is there is a way to really debug this situation?
  • Run wireshark or tcpdump or some other packet capture tool
  • Run your client & server under strace and make sure all the socket syscalls are shown, with accurate (and hopefully well-synchronized) timestamps
Useless
  • 64,155
  • 6
  • 88
  • 132
  • Oh okay thanks alot for the answer! the problem is that i have to use UDP because i want to stream data as fast as possible to the other side... for sure i have to sepend the time learning non-blocking UDP :) ... but which concept would u say it could be most appropriate for this case? do u have any idea? – Hilal Abu-Saleh Jun 22 '22 at 16:51
  • If you're really going as fast as possible, you need to decide how much reliability you need and figure out how to provide that. You have to assume that packets will get lost, and know whether you need to recover them, and if so how. It may make more sense to have a separate UDP receiver thread so you don't miss something while waiting on your UART – Useless Jun 22 '22 at 16:55