Link to home
Start Free TrialLog in
Avatar of cranium2003
cranium2003

asked on

Why getsockname will not work with udp sockets ?

HI,
                                       I want to get my local ethernet ip on which i receive a socket data. I have eth0: 10.0.0.100 and eth1:192.168.1.100 then how to know on which i receive socket data. I know that i only sending data from another pc eth:10.0.0.200 to 10.0.0.100. But how can i get that info in my udpServer.

I must have to set server socket with
          servAddr.sin_family = AF_INET;
          servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
          servAddr.sin_port = htons(LOCAL_SERVER_PORT);
then how t get my local IP?
                  I already use successfully getsockname with TCP sockets with no problem.
                 I am  USING RH LINUX OS.
Avatar of Narendra Kumar S S
Narendra Kumar S S
Flag of India image

With UDP, the address is already available with the received packet.
recvAddr.sin_addr.s_addr will be having that info.

-ssnkumar
Avatar of cranium2003
cranium2003

ASKER

Hello ssnkumar,
Why am i not able to get local ip address of my eth0 on which i think i am receiving socket data
as its configured to address 10.0.0.100 which my udpclient program takes.

PC2 has eth1
udpClient gives output as
./udpClient 10.0.0.100 string
./udpClient: sending data to '10.0.0.100' (IP : 10.0.0.100)

PC1 has eth0 and eth1
and udpServer as
./udpServer
./udpServer: waiting for data on port UDP 9200
remote ipaddress=10.0.0.0.200
./udpServer: from 10.0.0.0.200:UDP1024 : string
local ipaddress=0.0.0.0


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#define LOCAL_SERVER_PORT 9200
#define MAX_MSG 1024

int main(int argc, char *argv[]) {
 
  int sd, rc, n, cliLen,id,serlen;
  struct sockaddr_in cliAddr, servAddr,localaddr;
  char msg[MAX_MSG];

  sd=socket(AF_INET, SOCK_DGRAM, 0);
  if(sd<0) {
    printf("%s: cannot open socket \n",argv[0]);
    exit(1);
  }

  servAddr.sin_family = AF_INET;
  servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servAddr.sin_port = htons(LOCAL_SERVER_PORT);
  rc = bind (sd, (struct sockaddr *) &servAddr,sizeof(servAddr));
  if(rc<0) {
    printf("%s: cannot bind port number %d \n", argv[0], LOCAL_SERVER_PORT);
    exit(1);
  }

  printf("%s: waiting for data on port UDP %u\n", argv[0],LOCAL_SERVER_PORT);

  while(1) {
    memset(msg,0x0,MAX_MSG);
     
    cliLen = sizeof(cliAddr);
    n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr, &cliLen);
   
    if(n<0) {
      printf("%s: cannot receive data \n",argv[0]);
      continue;
    }
 
    printf("remote ipaddress=%s\n",inet_ntoa(cliAddr.sin_addr));
    printf("%s: from %s:UDP%u : %s \n", argv[0],inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port),msg);
    serlen=sizeof(servAddr);
    id= getsockname(sd,(struct sockaddr *) &servAddr,&serlen);
    printf("local ipaddress=%s\n",inet_ntoa(servAddr.sin_addr));
  }

return 0;

}
You are doing:
> servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
On the server.
Are you doing something similar on the client side also?

There is no problem on the server side.

-ssnkumar
hello ssnkumar,
             yes you are right and tell me if i am wrong in udpclient with its main code

int sd, rc, i;
  struct sockaddr_in cliAddr, remoteServAddr;
  struct hostent *h;

  if(argc<3) {
    printf("usage : %s <server> <data1> ... <dataN> \n", argv[0]);
    exit(1);
  }

  h = gethostbyname(argv[1]);
  if(h==NULL) {
    printf("%s: unknown host '%s' \n", argv[0], argv[1]);
    exit(1);
  }

  printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));
remoteServAddr.sin_family = h->h_addrtype;
  memcpy((char *) &remoteServAddr.sin_addr.s_addr,  h->h_addr_list[0], h->h_length);
  remoteServAddr.sin_port = htons(REMOTE_SERVER_PORT);

  sd = socket(AF_INET,SOCK_DGRAM,0);
  if(sd<0) {
    printf("%s: cannot open socket \n",argv[0]);
    exit(1);
  }
 
  cliAddr.sin_family = AF_INET;
  cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  cliAddr.sin_port = htons(0);
 
  rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
  if(rc<0) {
    printf("%s: cannot bind port\n", argv[0]);
    exit(1);
  }
for(i=2;i<argc;i++) {
    rc = sendto(sd, argv[i], strlen(argv[i])+1, 0,(struct sockaddr *) &remoteServAddr, sizeof(remoteServAddr));

    if(rc<0) {
      printf("%s: cannot send data %d \n",argv[0],i-1);
      close(sd);
      exit(1);
    }

  }
 
  return 1;

}
Hello ssnkumar,
         One more thing if my client is also having 2 or more ethernet cards then how can i set communication say among 5 computers who are sending strings to each other with every Pc then have server and client program running on it? What value should be plcaed in clients at each pc in structrure at client
 cliAddr.sin_family = AF_INET;
  cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  cliAddr.sin_port = htons(0);
 
>>>> I already use successfully getsockname with TCP sockets with no problem.

getsockname works on connected sockets created by an accept call of a TCP/IP server.

As UDP sockets are connectionless you couldn't get the information via getsockname.

>>>> if my client is also having 2 or more ethernet cards

By specifying INADDR_ANY you allow the underlying service provider to use any appropriate network address (network card).

Regards, Alex
> What value should be plcaed in clients at each pc in structrure at client
Whatever you are doing now is enough for that also.
The kernel itself chooses the correct card for communication.
So, you need not worry about that!

I tried your program on my system (Solaris).
Both of them are working fine and the server is getting the correct IP of the client.

So, please check the /etc/hosts file. It has to contain the correct IP for the given hostname.

-ssnkumar
Hello ssnkumar,
     Thats strange that my programs works fine on your system. I also got the desired output of local IP but what i have to change in my UDP sever program is that

while(1) {
    memset(msg,0x0,MAX_MSG);

    cliLen = sizeof(cliAddr);
    n = recvfrom(sd, msg, MAX_MSG, 0, (struct sockaddr *) &cliAddr, &cliLen);
   if(n<0) {
      printf("%s: cannot receive data \n",argv[0]);
      continue;
    }
>>>    n1= connect(sd,(struct sockaddr *) &cliAddr, cliLen);
   if(n1<0) {
      printf("%s: cannot connect socket \n",argv[0]);
      continue;
    }

    printf("remote ipaddress=%s\n",inet_ntoa(cliAddr.sin_addr));
    printf("%s: from %s:UDP%u : %s \n", argv[0],inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port),msg);
>>>    serlen=sizeof(servAddr);
>>>    id= getsockname(sd,(struct sockaddr *) &servAddr,&serlen);
>>>    printf("local ipaddress=%s\n",inet_ntoa(servAddr.sin_addr));
  }


 Also i kept INADDR_ANY at both UDP server as well as UDP client programs.
          Tell me how then it require me to add connect statement in Udp server program to have local IP on which i receive socket data?
I didn't know that you could connect to an UDP socket, but I was wrong. MSDN says:

---------------------------------------------------------------------------------------------------
For a connectionless socket (for example, type SOCK_DGRAM), the operation performed by connect is merely to establish a default destination address that will be used on subsequent send and recv calls. Any datagrams received from an address other than the destination address specified will be discarded ...
---------------------------------------------------------------------------------------------------

It seems to me that after the connect you should be able to call getsockname as you've been used with TCP sockets. But, you couldn't use the socket to send/receive to/from different addresses after establishing a connection.

Regards, Alex
ASKER CERTIFIED SOLUTION
Avatar of Narendra Kumar S S
Narendra Kumar S S
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hello ssnkumar & itsmeandnobodyelse,
                        I think ssnkkumar u r right. cause  my udpserver(on 10.0.0.100) got stuck when its receive first string from ip 10.0.0.200 udpclient program and then stops working without error.  My udpclient is doing its work of sending strings to udpserver
but besided having
udpClinet  first
sendto
recvfrom

udpserver
recvfrom
sendto

          why is that happening?? it happend when i try to use connect in udp. it seems that when i use connect, then I will be restricted to send to only one ip and one port and only single time though both are working in while loop to continuously receive and send strings to each other.


             
 

>>>> it seems that when i use connect, then I will be restricted to send to only one ip and one port

Yes, a connect turns the formerly connection-less socket, so you couldn't send/recv to/from other IP addresses. If that isn't intended you should omit the connect and get the sender's IP address from the received packet as ssnkumar already has suggested.

Note, if you would configure multiple network cards to have disjoint subnets via subnet mask, you always could figure out what device was used by analysing the IP address (sender and destination).

Regards, Alex
hello,
       >>Yes, a connect turns the formerly connection-less socket, so you couldn't send/recv to/from other IP addresses
        But also not from same udp connection in while loop once i connect in udpserver it stops receiving from client. Is that right?
>>If that isn't intended you should omit the connect and get the sender's IP address from the received packet as ssnkumar already has suggested.
      No i know how to get sender's ip. I want to get local ethernet IP (provided SERVER AND CLIENT have (INADDR_ANY) at socket address) on which i received socket data  in both UDP server and TCP server programs.
        How to do that then?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial