Unable to create a UDP client from thread?

I try to initial a UDP client from threading, but it doesn't work? why?

These codes from the textbook

#define ECHOMAX         255     /* Longest string to echo */
#define TIMEOUT_SECS    2       /* Seconds between retransmits */
#define MAXTRIES        5       /* Tries before giving up */
int tries=0;   /* Count of times sent - GLOBAL for signal-handler access */
void CatchAlarm(int ignored)     /* Handler for SIGALRM */
{
    tries += 1;
}
static void DieWithError(char *errorMessage)
{
    perror(errorMessage);
    exit(1);
}
void TCP () {
    int sock;                        /* Socket descriptor */
    struct sockaddr_in echoServAddr; /* Echo server address */
    struct sockaddr_in fromAddr;     /* Source address of echo */
    unsigned short echoServPort;     /* Echo server port */
    unsigned int fromSize;           /* In-out of address size for recvfrom() */
    struct sigaction myAction;       /* For setting signal handler */
    char *servIP;                    /* IP address of server */
    char *echoString;                /* String to send to echo server */
    char echoBuffer[ECHOMAX+1];      /* Buffer for echo string */
    int echoStringLen;               /* Length of string to echo */
    int respStringLen;               /* Size of received datagram */

//The IP is invalid since I need to test the function about timeout!!
    servIP = "192.168.1.254";           /* First arg:  server IP address (dotted quad) */
    echoString = "abc";       /* Second arg: string to echo */

    if ((echoStringLen = strlen(echoString)) > ECHOMAX)
        DieWithError("Echo word too long");

        echoServPort = atoi("12345");  /* Use given port, if any */

    /* Create a best-effort datagram socket using UDP */
    if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
        DieWithError("socket() failed");

    /* Set signal handler for alarm signal */
    myAction.sa_handler = CatchAlarm;
    if (sigfillset(&myAction.sa_mask) < 0) /* block everything in handler */
        DieWithError("sigfillset() failed");
    myAction.sa_flags = 0;

      if (sigaction(SIGALRM, &myAction, 0) < 0)
        DieWithError("sigaction() failed for SIGALRM");

    /* Construct the server address structure */
    memset(&echoServAddr, 0, sizeof(echoServAddr));    /* Zero out structure */
    echoServAddr.sin_family = AF_INET;
    echoServAddr.sin_addr.s_addr = inet_addr(servIP);  /* Server IP address */
    echoServAddr.sin_port = htons(echoServPort);       /* Server port */

    /* Send the string to the server */
    if (sendto(sock, echoString, echoStringLen, 0, (struct sockaddr *)
               &echoServAddr, sizeof(echoServAddr)) != echoStringLen)
        DieWithError("sendto() sent a different number of bytes than expected");

    /* Get a response */
    fromSize = sizeof(fromAddr);
    alarm(TIMEOUT_SECS);        /* Set the timeout */
  When I call this function from a thread, it is blocking here, and no response anymore!
    while ((respStringLen = recvfrom(sock, echoBuffer, ECHOMAX, 0,
           (struct sockaddr *) &fromAddr, &fromSize)) < 0) {
        if (errno == EINTR)     /* Alarm went off  */
        {
            if (tries < MAXTRIES)      /* incremented by signal handler */
            {
                printf("timed out, %d more tries...\n", MAXTRIES-tries);
                if (sendto(sock, echoString, echoStringLen, 0, (struct sockaddr *)
                            &echoServAddr, sizeof(echoServAddr)) != echoStringLen)
                    DieWithError("sendto() failed");
                alarm(TIMEOUT_SECS);
            }
            else
                DieWithError("No Response");
        }
        else
            DieWithError("recvfrom() failed");
    }

    /* recvfrom() got something --  cancel the timeout */
    alarm(0);

    /* null-terminate the received data */
    echoBuffer[respStringLen] = '\0';
    printf("Received: %s\n", echoBuffer);    /* Print the received data */

    close(sock);
    exit(0);
}

These code does not work!

static void* testRun () {
    TCP();
    pthread_exit(NULL);
    return NULL;
}
int main ( void ) {
    pthread_t thread1;
    assert( pthread_create( &thread1, NULL, &testRun, NULL) == 0 );
    assert( pthread_join( thread1, NULL) == 0 );
    while ( 1 ) {}
}

The following codes work!!! WHY? WHY? I ready have no idea!

 
int main ( void ) {
 TCP();
 while ( 1 ) {}
}

---------- Post updated at 12:30 PM ---------- Previous update was at 11:40 AM ----------

The problem properly cause by the signal and threading. But I still have no idea.

Have a look at pthread_sigmask.

Hi,

The answer from fpmurphy is short, but up to the point. Let me explain a little bit; In a multi-threaded process, a signal handler process-wide, that is global to all threads. However, when the signal is delivered, the system library / kernel picks up a particular thread that shall run the handler. This might be any thread in the process.

In your particular example, you wish that the handler runs in the context of thread1, so that the recvfrom() gets interrupted. But, unless you force it too, the handler may run in the context of the main thread. In that case, nothing will happen. This is likely what you are experiencing.

The way to force the handler to run in the context of thread1 (or equivalently, we say the signal to be delivered to thread1) is using pthread_sigmask() as mentioned by fpmurphy. Please refer to example in the link provided above, to see how it works. Incidentally, this example was my first contribution to the SUSv3 standard; so if you have questions please feel free to ask :slight_smile:

And finally, I would suggest to resort other strategies than alarm() & co. to implement a timeout on the receive operation if you're multi-threaded.

Cheers, Lo�c.

Thanks, I will try it today.