简体   繁体   中英

Socket Programming (Client - Server UDP)

I would like to build a client - server model where, for any number of clients connected to the server, the server should send a broadcast Message. Below is the code which I implemented, it does not throw any error, but I could not see any communication happening between the server and the client. Please let me know, where is the problem in the code.

I would like to see the message passed from the server on the clients system.

    /************* UDP SERVER CODE *******************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]){
  int udpSocket, nBytes, buflen;
  char buffer[1024];
  char string[1024];
  int portNum;
  struct sockaddr_in serverAddr, clientAddr;
  struct sockaddr_storage serverStorage;
  socklen_t addr_size, client_addr_size;
  int i;

  /*Create UDP socket*/
  udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
  portNum=atoi(argv[1]);
  /*Configure settings in address struct*/
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(5000);
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.117");

  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  

  /*Bind socket with address struct*/
  int bStatus=bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
   if (bStatus < 0) {
        printf("error binding on server's port number\n"); 
        exit(1);
  }     


  /*Initialize size variable to be used later on*/
  addr_size = sizeof serverStorage;

memset(&clientAddr, 0, sizeof(clientAddr));
  clientAddr.sin_family = AF_INET;
  clientAddr.sin_port = htons(portNum);  // this is where client is bound
  clientAddr.sin_addr.s_addr = inet_addr("192.168.1.114");

  while(1){
sprintf(buffer,"Hello Client");
  buflen=strlen(buffer);
  int bytesSent = sendto(udpSocket,buffer,buflen,0,(struct sockaddr *)&clientAddr, sizeof(clientAddr));
  if (bytesSent < 0) {
        printf("Error sending/ communicating with client\n");
        exit(1);
  }
  printf("%s\n",buffer);

/*
// ****************************************************

memset(buffer, 0, 1024);
buflen=65536;
recvfrom(udpSocket,buffer,buflen,0,(struct sockaddr *)&serverStorage, &addr_size);
printf("Received from server: %s\n",buffer);  

*/
}

  return 0;
}

Below is the client code :

     /************* UDP CLIENT CODE *******************/

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(int argc, char *argv[]){
  int clientSocket, portNum, nBytes, buflen;
  char buffer[1024];
  char string[1024];
  struct sockaddr_in serverAddr,clientAddr;
  socklen_t addr_size;

  /*Create UDP socket*/
  clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
 portNum = atoi(argv[1]);
  /*Configure settings in address struct*/
  serverAddr.sin_family = AF_INET;
  serverAddr.sin_port = htons(portNum);
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.117");

//  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  
memset(&serverAddr,0,sizeof(serverAddr));


// binding 
bind(clientSocket, (struct sockaddr *) &clientAddr, sizeof(clientAddr));


  /*Initialize size variable to be used later on*/
  addr_size = sizeof serverAddr;

  while(1){

memset(buffer, 0, 1024);
buflen=65536;
recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size);
//recvfrom(clientSocket,buffer,buflen,0,NULL,NULL);
printf("Received from server: %s\n",buffer);

/*
//********************************************************************

sprintf(buffer,"Hello Client");    
 buflen=strlen(buffer);
 sendto(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr,addr_size);
 printf("%s\n",buffer);
*/
}

return 0;
}

At a high level there are a few things that need to be addressed. Given the code in the post has a server that initiates communication with the client following line needs to be modified (and related code for these)

On the server side:

  sendto(udpSocket,buffer,buflen,0,(struct sockaddr *)&serverStorage,addr_size);

Essentially what's happening here is that udpSocket is bound to serverAddr and we are trying to sendto serverStorage (2nd last argument). The trouble here is that the serverStorage is not bound to anything. Basically sendto has the source right but not the destination.

On the client side:

recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size);

The clientSocket is not bound to anything so the system picks a random port where it will listen. In the recvfrom call, 2nd last argument captures the address details of the other side. Whereas in the code you have bound it to server's IP and port, it does not have any effect because it is filled in by the recvfrom call and returned.

To make things work here is what I'd suggest (you can add the details but have worked out the skeleton based on what you posted)

server_initiating_with_client.c

    //...
    int udpSocket, nBytes, buflen;
    char buffer[1024];
    int portNum;
    struct sockaddr_in serverAddr, clientAddr;
    struct sockaddr_storage serverStorage;
    socklen_t addr_size, client_addr_size;

    /*Create UDP socket*/
    udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
    portNum=atoi(argv[1]);
    /*Configure settings in address struct*/
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(5000);   // Making sure server has a unique port number
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    /*Bind socket with address struct*/
    int bStatus = bind(udpSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
    if (bStatus < 0) {
        printf("error binding on server's port number\n");
        exit(1);
    }

    /*Initialize size variable to be used later on*/
    addr_size = sizeof serverStorage;

    /* Because server is initiating the communication here one needs to set the
     * clientAddr and needs to know the port number of the client
     */
    memset(&clientAddr, 0, sizeof(clientAddr));
    clientAddr.sin_family = AF_INET;
    clientAddr.sin_port = htons(portNum);
    clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    while(1){
        sprintf(buffer,"Hello Client");   
        buflen=strlen(buffer);
        int bytesSent = sendto(udpSocket,buffer,buflen, 0,
            (struct sockaddr *)&clientAddr, 
            sizeof(clientAddr));
        if (bytesSent < 0) {
            printf("Error sending/ communicating with client\n");
            exit(1);
        }
            printf("Done sending %s\n", buffer);
                sleep(1);
    }
    ..

and on the client side something along these lines

    //..
    int clientSocket, portNum, nBytes, buflen;
    char buffer[1024];
    struct sockaddr_in serverAddr;
    struct sockaddr_in clientAddr;
    socklen_t addr_size;

    /*Create UDP socket*/
    clientSocket = socket(PF_INET, SOCK_DGRAM, 0);
    portNum = atoi(argv[1]);
    /*Configure settings in address struct*/
    memset(&clientAddr, 0, sizeof(clientAddr));
    clientAddr.sin_family = AF_INET;
    clientAddr.sin_port = htons(portNum);
    clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    memset(&serverAddr, 0, sizeof(serverAddr));


    /*Bind on client side as well because you are specifically sending something over
    * to the client. Usually the server will know where to talk back to the client
    * but in your example because of the reversed semantics this will be needed
    */

    bind(clientSocket, (struct sockaddr *) &clientAddr, sizeof(clientAddr));

    /*Initialize size variable to be used later on*/
    addr_size = sizeof serverAddr;

    while(1){
        memset(buffer, 0, 1024);
        buflen=65536;
        recvfrom(clientSocket,buffer,buflen,0,(struct sockaddr *)&serverAddr, &addr_size);
        printf("Received from server: %s\n",buffer);
        sleep(1);
    }
    return 0;

The code can be simplified if you reverse your comm from client to server, thereby, eliminating the need for a fixed port number on the client side.

just make a few changes in it. Assign a socket length predefined (socklen_t *) structure to typecast length

n = recvfrom(sockfd, (char *)buffer, MAXLINE,MSG_WAITALL, (struct sockaddr *) &servaddr,  (socklen_t*)&len); 

socklen_t* convert a length into socket length. Make these changes at both client-side as well as a server-side .


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