简体   繁体   中英

How would I go about making this udpclient asynchronous using pthreads?

How would I go about making this udpclient asynchronous using pthreads? I want to make sure UDP datagram won't be lost and also don't want the client program to wait forever and not be able to send any more messages

/*udpclient.c program */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
/* Here are some details of the sockaddr_in structure and the sockaddr structure
   These declarations are copied from winsock.h

   struct in_addr {       this struct holds a 32 bit IP address
        union {
                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
                struct { u_short s_w1,s_w2; } S_un_w;
                u_long S_addr;
        } S_un;
#define s_addr  S_un.S_addr

    struct sockaddr_in {   notice this structure is 16 bytes long
            short       sin_family;
            u_short     sin_port;
            struct      in_addr sin_addr;
            char        sin_zero[8];
     };
        struct sockaddr {       this generic address structure is 16 bytes long, too!
            u_short sa_family;
            char        sa_data[14];
     };

*/
/* we have to send on the same port the server is listening on */
#define PORT 20009
/* simple upd client */
int main()
{
#ifdef WIN
      SOCKET sock;
#else
      int sock;
#endif
      int size;
      int nbytes, flags;
      int i;
      char * cp;
#ifdef WIN
      WSADATA wsaData;
      int nCode;
#endif
      char buffer[100];
      char str_addr[20];        /* holds the chars of an IP address */
      struct sockaddr_in target_pc, me;

/* magic call to initialize the network I/O code - only Microsoft requires this */
#ifdef WIN
      if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
      printf("Opps! WSA error %d\n",nCode);
      return -1;
      }
#endif
/* create a socket to send on */
      sock = socket(PF_INET,SOCK_DGRAM,0);
       if(sock < 0) {
       printf("socket error = %d\n", sock);
       return -1;
       }
      /* we fill in the address family and port, but we do not know the destination IP address yet */
      target_pc.sin_family = PF_INET;
      target_pc.sin_port = htons(PORT);
      /* fill in my address and port */
      me.sin_family = PF_INET;
      me.sin_port = htons(0);
      me.sin_addr.s_addr = htonl(INADDR_ANY);
      i = bind(sock, (struct sockaddr *) &me, sizeof(me));
      if( i < 0) {
          printf("bind result: %d\n", i);
          return -1;
          }


      nbytes = 99;

      while(1){
            printf("Enter the target IP address: ");
            cp = fgets(str_addr,19,stdin);
            /* remove the \n */
            str_addr[strlen(str_addr)-1] = '\0';
            /* the inet_addr function converts a string form of IP address to a 32 binary integer */
            target_pc.sin_addr.s_addr = inet_addr(&str_addr[0]);
            printf("Enter your message: ");
            cp = fgets(buffer,99,stdin);
            /* get the string length so we send exactly this many characters */
            nbytes = strlen(buffer);
            flags = 0;
            size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,sizeof(target_pc));
            printf("msg size = %d size = %d\n", nbytes, size);

            //added

            int addrlen = sizeof(target_pc);
            size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,&addrlen);
            if((size > 0) && (size < 99)){
               buffer[size] = '\0';      //add the null byte so buffer now holds a string 
               i = puts((char *) buffer);    // write this string to the display 
            }

      }
#ifdef WIN
      system("PAUSE");
#endif
      return 0;
}

/ udpserver.c program /

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#define PORT 20009
/* simple upd server 
   this program receives short messages (<99 characters) from any IP address
   and writes them to the display
   be sure to use the linker line option "-l wsock32"
*/
int main()
{
    /* first define a socket
    a socket is an I/O port like a file descriptor
    */
#ifdef WIN
      SOCKET sock;   /* SOCKET is a typedef for a structure */
#else
      int sock;
#endif
      int size;
      int nbytes, flags;
#ifdef WIN
      int addrlen;
#else
      socklen_t addrlen;
#endif
      int i;
      /* char loopback[20]="127.0.0.1"; */
#ifdef WIN
      WSADATA wsaData;              /* This is struct holds Windows required data */
      int nCode;
#endif
      char buffer[100];
      struct sockaddr_in server;    /* this holds my IP address and port info */
      struct sockaddr_in from;      /* this holds the same info for the sender of the packet
                                       I received */
      /* the call to WSAStartup is Windows magic */
#ifdef WIN
      if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
      printf("Opps! WSA error %d\n",nCode);
      exit;
      }
#endif
      /* create a socket called sock. It is a datagram socket */
      sock = socket(AF_INET,SOCK_DGRAM,0);
       if(sock < 0){
       printf("socket error = %d\n", sock);
       return -1;
       }
      server.sin_family = AF_INET;   /* initialize the server address family */
      server.sin_addr.s_addr = htonl(INADDR_ANY); /* notice this struct within a struct */
      /* printf("%x\n",server.sin_addr.s_addr); */
      server.sin_port = htons(PORT);
      /* associate the socket with the address structure - this is called binding */
      i = bind(sock, (struct sockaddr *) &server, sizeof(server));
      if( i < 0) {
          printf("bind result: %d\n", i);
          return -1;
          } else
          printf("Simple UDP server is ready!\n\n");
      nbytes = 99; /* receive packets up to 99 bytes long */
       flags = 0;  /* must be zero or this will not work! */
      while(1){
      /* the recvfrom function is a read and the arguments are:
             sock - the socket we are reading
             buffer - array into which to read the data
             nbytes - read up to this many bytes
             flags - used for special purposes - not needed here
             from - sockaddr struct to hold the IP address and port of the sender of the packet
             addrlen - the size of the sockaddr struct written by this function
      */
         addrlen = sizeof(from);
         size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&from, &addrlen);
         if((size > 0) && (size < 99)){
         buffer[size] = '\0';      /* add the null byte so buffer now holds a string */
         i = puts((char *) buffer);    /* write this string to the display */
         }

         //echo message back to client

         if(sock < 0) {//
             printf("socket error = %d\n", sock);//
             return -1;//
         }//

         sendto(sock, buffer, nbytes, flags, (struct sockaddr *)&from,addrlen); //
      }

#ifdef WIN
      system("PAUSE");
#endif
      return 0;
}

We could create two threads: one for the sendto (that waits for the user input) and the other for recvfrom(). Next, we can have the recvrom() use Pthread condvar (by calling pthread_cond_wait() on a condvar and a Pthread mutex) and wait. When the user provides an input, we can sendto (which is not really blocking) and then call pthread_cond_signal() to wake up the other thread.

You could certainly simply this, if you wanted. If your application permits, you could completely skip the pthread_cond_wait() since recvfrom() is anyways a blocking call. So, this way, recvfrom() would block but then it would go out of sync with the send calls. The other option is to use the main() thread for the sendto() thread -- in that case, you would just need one additional thread for the recv calls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM