简体   繁体   中英

Trying to make udp server echo back to udp client and print on the screen, as well have udp client receive messages

I'm trying to modify these two programs. I want to have udpclient.c be able to receive messages and have udpserver.c echo the message back to the client. I'd also like to have the udpclient time tag messages before it sends them. Received messages should result in the IP address of the server and the Round Trip Time (RTT) being printed on the client side. When I test it, client sends and server receives but server does not echo back message. The place that I attempted to modify is in the infinite while loop of each program afer "//added"

udpclient.c

#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

#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 */
         }

       //added
       sock = socket(PF_INET,SOCK_DGRAM,0);//
       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;
}

(If you read my earlier answer, please ignore it. It was incorrect.)

You missed a '&' in front of addrlen on line 82 in udpserver.c. It should be:

size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&from, &addrlen);

Other than that your code is working fine (I ran it). However, there are three things I would like to mention:

  1. The client does not need to to bind his socket to receive messages from the server.
  2. The server does not need to create a new socket to send messages to the client. Just use the socket you called recvfrom with.
  3. Sockets should be closed once they are not used anymore (even at the end of the program). Having too many open sockets will lead to not being able to create any new socket.

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