ОС : Ubuntu (Linux) 

Below is my class Server . There is a void myListen() method in which I try to extract server and client IPs. With the client, everything goes, but the server's IP address seems to me as 0.0.0.0 , which, of course, does not suit me. How to get a real ip to which the client is connected?

 class Server{ private: int sockfd, newsockfd, portno, pid; struct sockaddr_in serv_addr, cli_addr, *tmp_addr_in; socklen_t clilen, servlen; struct sockaddr *tmp_addr; public: Server(int port) : portno(port) { sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); } ~Server(){ close(sockfd); } void myListen(){ listen(sockfd,5); clilen = sizeof(cli_addr); char bufClientIp[64]; char bufServerIp[64]; while (1) { newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); inet_ntop(AF_INET, &cli_addr.sin_addr, bufClientIp, INET_ADDRSTRLEN); struct sockaddr sa; servlen = sizeof(tmp_addr); if(getsockname(sockfd, &sa, &servlen) == -1){ error("ERROR on getsockname"); } tmp_addr_in = (sockaddr_in*)tmp_addr; inet_ntop(AF_INET, &(tmp_addr_in->sin_addr), bufServerIp, INET_ADDRSTRLEN); std::cout<<"Server -> "<<bufServerIp<<std::endl; std::cout<<"Client -> "<<bufClientIp<<std::endl; if (newsockfd < 0) error("ERROR on accept"); pid = fork(); if (pid < 0) error("ERROR on fork"); if (pid == 0) { while(1){ close(sockfd); myReceive(); } exit(0); } else close(newsockfd); } /* end of while */ } void myReceive (){ int bitsReceived; char buffer[256]; bzero(buffer,256); bitsReceived = read(newsockfd, buffer, 255); if (bitsReceived < 0) error("ERROR reading from socket"); printf("Here is the message: %s\n", buffer); bitsReceived = write(newsockfd,"I got your message",18); if (bitsReceived < 0) error("ERROR writing to socket"); } }; 

DECISION :

Based on the example of Mr. avp, I changed my void myListen() function to a working state and in the private section I changed the type cli_addr from struct sockaddr_in to struct sockaddr :

 void myListen(){ listen(sockfd,5); std::string szClientIp; std::string szServerIp; int szClientPort; int szServerPort; while (1) { newsockfd = accept(sockfd, &cli_addr, &clilen); if (getpeername(newsockfd, &cli_addr, &clilen) == -1) perror("getpeername"); else szClientIp = inet_ntoa(((struct sockaddr_in *)&cli_addr)->sin_addr); szClientPort = ntohs(((struct sockaddr_in *)&cli_addr)->sin_port); std::cout<<"Client Ip : > "<<szClientIp<<std::endl; std::cout<<"Client Port : > "<<szClientPort<<std::endl; if (getsockname(newsockfd, &cli_addr, &clilen) == -1) perror("getsockname"); else szServerIp = inet_ntoa(((struct sockaddr_in *)&cli_addr)->sin_addr); szServerPort = ntohs(((struct sockaddr_in *)&cli_addr)->sin_port); std::cout<<"Server Ip : > "<<szServerIp<<std::endl; std::cout<<"Server Port : > "<<szServerPort<<std::endl; if (newsockfd < 0) error("ERROR on accept"); pid = fork(); if (pid < 0) error("ERROR on fork"); if (pid == 0) { while(1){ close(sockfd); myReceive(); } exit(0); } else close(newsockfd); } /* end of while */ 

    1 answer 1

    From the question it is absolutely not clear what exactly is not working.

    ======

    Update after the appearance of the code

    Your mistakes here

     servlen = sizeof(tmp_addr); // видим struct sockaddr *tmp_addr и похоже это не тот размер -) if(getsockname(sockfd, &sa, &servlen) == -1){ error("ERROR on getsockname"); } tmp_addr_in = (sockaddr_in*)tmp_addr; // этот указатель 

    Looks unknown where.

     inet_ntop(AF_INET, &(tmp_addr_in->sin_addr), // вот тут Вам не повезло, прога НЕ УПАЛА (а то, сами бы в отладчике нашли) bufServerIp, INET_ADDRSTRLEN); 

    And they are all associated with tmp_addr_in and tmp_addr .

    Looks like you just need to write

     servlen = sizeof(sa); if(getsockname(sockfd, &sa, &servlen) == -1){ error("ERROR on getsockname"); } inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr, // видимо тут-то Вы и запутались bufServerIp, INET_ADDRSTRLEN); 

    ======

    I would venture to suggest that the variable clilen not initialized before calling accept() .

    B man 2 accept is written:

      The addrlen argument is a value-result argument: the caller must ini‐ tialize it to contain the size (in bytes) of the structure pointed to by addr; on return it will contain the actual size of the peer address. 

    Those. write:

     socklen_t clilen = (__typeof__(clilen))sizeof(cli_addr); 

    before calling accept() (which can change its value).

    In addition, having a "legitimate" socket, it does not matter at the client or server, you can always find out as your own address (IP, port)

     int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 

    so and address "vis"

     int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); 

    In both cases, the addrlen parameter must be initialized before the call (similar to the accept() example) in the buffer size for the address pointed to by *addr .

    Here is an example:

     avp@wubu:hashcode$ cat serv-ips.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static int makeSimpleServer (char *cport) // default port = 12345 { int on = 1, asock = socket (AF_INET, SOCK_STREAM, 0); if (setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) errExit("socket"); short port = cport? atoi(cport): 12345; if (port < 1) port = 12345; struct sockaddr_in addr; int laddr = sizeof(addr); memset (&addr, 0, laddr); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(asock, (struct sockaddr *)&addr, laddr)) errExit("bind"); struct linger ling; ling.l_onoff = 1; ling.l_linger = 2; // seconds after shudown sock for deliver data if (setsockopt(asock, SOL_SOCKET, SO_LINGER, (char *)&ling, sizeof(ling))) errExit("linger"); if (listen(asock, 128)) errExit("listen"); return asock; } int main (int ac, char *av[]) { // port av[1] (default 12345) and INADDR_ANY int asock = makeSimpleServer(av[1]); int sock; struct sockaddr inadr; socklen_t slen = sizeof(inadr); while ((sock = accept(asock, &inadr, &slen)) > 0) { printf ("New connection %s:%d\n", inet_ntoa(((struct sockaddr_in *)&inadr)->sin_addr), ntohs(((struct sockaddr_in *)&inadr)->sin_port)); if (getpeername(sock, &inadr, &slen) == -1) perror("getpeername"); else printf("getpeername %s:%d\n", inet_ntoa(((struct sockaddr_in *)&inadr)->sin_addr), ntohs(((struct sockaddr_in *)&inadr)->sin_port)); if (getsockname(sock, &inadr, &slen) == -1) perror("getsockname"); else printf("getsockname %s:%d\n", inet_ntoa(((struct sockaddr_in *)&inadr)->sin_addr), ntohs(((struct sockaddr_in *)&inadr)->sin_port)); close(sock); errno = 0; } perror("server exit"); } avp@wubu:hashcode$ gcc serv-ips.c && ./a.out New connection 10.3.35.78:46980 getpeername 10.3.35.78:46980 getsockname 10.3.35.78:12345 New connection 127.0.0.1:50958 getpeername 127.0.0.1:50958 getsockname 127.0.0.1:12345 ^C avp@wubu:hashcode$ 

    in another window, respectively, ran

     avp@wubu:~$ nc 10.3.35.78 12345 avp@wubu:~$ nc localhost 12345 

    As you can see, everything works for me.

    Update

    Considered that you have a problem with calling inet_ntop() ...
    According to man inet_ntop

     The resulting string is copied to the buffer pointed to by dst, which must be a non-null pointer. The caller specifies the number of bytes available in this buffer in the argument size. 

    ....

      AF_INET src points to a struct in_addr (in network byte order) which is converted to an IPv4 network address in the dotted-decimal format, "ddd.ddd.ddd.ddd". The buffer dst must be at least INET_ADDRSTRLEN bytes long. 

    In the example code, it should be called like this:

     char buf[64]; inet_ntop(AF_INET, &((struct sockaddr_in *)&inadr)->sin_addr, buf, sizeof(buf) - 1) 

    I checked, really the results are the same as when calling inet_ntoa(...)

    • I have changed the description. Look, please. I tried to use getsockname, but it returns me 0.0.0.0 - Ligvest O
    • It getsockname(newsockfd, &sa, &servlen) - i.e. the socket you are working with, and not the one to which the connections come. So that's all right too - the zeros are INADDRANY, i.e. Accepted from any interface - avp
    • I know about INADDRANY. I don’t understand how to get exactly an IP address that I’m connected to, so that they are not zeros, but a real address. I tried the getsockname options (newsockfd, & sa, & servlen); getpeername (newsockfd, & sa, & servlen); getsockname (sockfd, & sa, & servlen); getpeername (sockfd, & sa, & servlen); But they all show zeros. Called these functions in the same place. - Ligvest O
    • Do you need server side (after accept)? - avp
    • Updated answer code example (everything works) - avp