user2104647
user2104647

Reputation: 31

UDP Sockets in C: client1 to server to client2

I have a UDP client/server that sends a message to a server in lower or uppercase. The server receives the message and relays it back with switched cases. I can't figure out how I would instead of having the server relay it back to the first client, instead sending it to a client2. If my client2 sends a message the server receives and sends it back to client2 and same thing with client1. I want what client1 says to be sent to the server and then the server send that to client2. I've tried everything i can think of but cant figure out.

Server:

/*
Simple udp server

*/
#include<stdio.h>   //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>

#define BUFLEN 512  //Max length of buffer
#define PORT 8888   //The port on which to listen for incoming data

void die(char *s)
{
    perror(s);
exit(1);
}

int main(void)
{
struct sockaddr_in si_me, si_other, si_other2;

int s, i, slen = sizeof(si_other) , recv_len;
char buf[BUFLEN];

//create a UDP socket
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
    die("socket");
}

// zero out the structure
memset((char *) &si_me, 0, sizeof(si_me));

si_me.sin_family = AF_INET;
si_me.sin_port = htons(PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);

//bind socket to port
if( bind(s , (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
    die("bind");
}

//keep listening for data
while(1)
{
    printf("Waiting for data...");
    fflush(stdout);

    //try to receive some data, this is a blocking call
    if ((recv_len = recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen)) == -1)   // read datagram from server socket
    {
        die("recvfrom()");
    }

    //print details of the client/peer and the data received
    printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));         printf("Data: %s\n" , buf);

    //now reply to server socket/the client with the same data
    if (sendto(s, buf, recv_len, 0, (struct sockaddr*) &si_other, slen) == -1)
    {
        die("sendto()");
    }



}

close(s);
return 0;
}

The Client:

/*
Simple udp client

*/
#include<stdio.h>   //printf
#include<string.h> //memset
#include<stdlib.h> //exit(0);
#include<arpa/inet.h>
#include<sys/socket.h>
#include<ctype.h>

#define SERVER "192.x.x.x"
#define BUFLEN 512  //Max length of buffer
#define PORT 8888   //The port on which to send data

void die(char *s)
{
perror(s);
exit(1);
}

int main(void)
{
struct sockaddr_in si_other;
int s, s2, i, slen=sizeof(si_other);
char buf[BUFLEN];
char message[BUFLEN];

if ( (s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)        // create a client socket
{
    die("socket");
}

memset((char *) &si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(PORT);

if (inet_aton(SERVER , &si_other.sin_addr) == 0)            // Create datagram with server IP and port.
{
    fprintf(stderr, "inet_aton() failed\n");
    exit(1);
}

while(1)
{
    printf("Enter message : ");
    gets(message);


    int a;
    char message2[BUFLEN];
    for(a=0;a<=BUFLEN-1;a++)
      {
        if(message[a] >= 97 && message[a] <= 122)
           message2[a] = toupper(message[a]);
        else
           message2[a] = tolower(message[a]);

      }


    if (sendto(s, message2, strlen(message2) , 0 , (struct sockaddr *) &si_other, slen)==-1)
    {
        die("sendto()");
    }


    //receive a reply and print it
    //clear the buffer by filling null, it might have previously received data
    memset(buf,'\0', BUFLEN);
    //try to receive some data, this is a blocking call
    if (recvfrom(s, buf, BUFLEN, 0, (struct sockaddr *) &si_other, &slen) == -1)        // read datagram from client socket
    {
        die("recvfrom()");
    }

    puts(buf);
}

close(s);
return 0;
}

Upvotes: 0

Views: 1749

Answers (2)

alecov
alecov

Reputation: 5162

After you read() or recvfrom() your message, you process your data and then sendto() twice: one to the address returned by recvfrom() (the original sender) and other to the other client's address (which must be provided or detected somehow by your server).

Something along this (proper error checking not being performed):

char data[100];
struct sockaddr_in address;
socklen_t length = sizeof address;

/* Receive data from any client. */
ssize_t result = recvfrom(server, data, sizeof data, 0, &address, &length);

/* Process the data (change cases). */
process_data(data, result);

/* Send back to the first client. */
sendto(server, data, result, 0, &address, sizeof address);

/* Check who's the sender and relay to the other. */
if (address.sin_addr.s_addr == CLIENT1_ADDRESS)
    address.sin_addr.s_addr = CLIENT2_ADDRESS;
else
    address.sin_addr.s_addr = CLIENT1_ADDRESS;

/* Send to the other client. */
sendto(server, data, result, 0, &address, sizeof address);

In this example, the addresses are statically defined.

Upvotes: 1

RAVI TANDON
RAVI TANDON

Reputation: 41

It seems instead of a UDP server, you want to have a forwarder of packets like from client->server->client2, so you need to tell your server the ipaddress/port of client2, for this kindly configure client2 ip/port in server either using commandline arguments or read any input file, then before the sendto statement in server code, fill the si_other structure with client2 information as teken from command line or input file.

Upvotes: 1

Related Questions