在服务器模式下如何发现连接的TCP套接字的本地IP地址

时间:2019-04-08 14:42:36

标签: c linux sockets networking tcp

我有一个常规的C语言Linux,TCP服务器应用程序,该应用程序需要接受多个本地地址上的连接,并且该程序必须能够发现每个不同会话使用的是哪个特定本地地址。 系统调用getsockname()从表面上看是适当的,但是在特定情况下,此API仅返回通配符地址0.0.0.0,其中,这是侦听套接字的绑定地址。 在绑定到显式地址的多个套接字上显式侦听的选项没有用,因为此要求可以正确地使用无法预先知道的地址(例如回送地址的变体(127.0.0.2、127.0.0.3,...)和动态分配的“次要”地址。 为了清楚起见,执行流程为“ socket”,“ bind”,“ listen”,“ accept”;而所讨论的套接字是'accept'返回的套接字。

1 个答案:

答案 0 :(得分:1)

回答我自己的问题-答案是,正确完成操作后,该操作确实按我最初希望的那样工作。解决方案在于严格遵守'gettpeername'和'getsockname'系统调用的用法,尤其要注意在进入之前设置的'socklen'参数-服务不仅返回被写入的字节数,而且返回相同的参数。也用于指示呼叫者提供了多少空间来接收响应。通过将对inet_ntoa()的调用堆叠在单个printf()中,调试变得更加复杂,inet_ntoa()会在每次调用时覆盖其先前的返回值。我发布了一个工作片段的示例,并感谢@John Bollinger鼓励我提出一个“最小的完整且可验证的”示例。我做了,它(几乎)第一次起作用。谢谢约翰。

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#define MAXPENDING 5    // Max connection requests
#define SOCKADDRSIZE (sizeof (struct sockaddr_in))

int main (int argc, char** argv) {

socklen_t addrsize;
int serversock,
    peersock;
struct sockaddr_in sockaddr;

sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);   // local server addr - wildcard
sockaddr.sin_port = htons(179);       // BGP server port

serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
bind(serversock, &sockaddr, SOCKADDRSIZE);
printf("\nlistening\n");
listen(serversock, MAXPENDING);

while (1) {
// without the following statement the return value appears to show the wildcard address
//  (actually it is simply unmodified memory which may happen to be zeros)
  addrsize = SOCKADDRSIZE;
  peersock = accept(serversock, &sockaddr, &addrsize );
  printf("\nconnected\n");
  printf("accept address %s\n", inet_ntoa(sockaddr.sin_addr));

  addrsize = SOCKADDRSIZE;
  getsockname(peersock,&sockaddr,&addrsize);
  printf("local address %s\n", inet_ntoa(sockaddr.sin_addr));

  addrsize = SOCKADDRSIZE;
  getpeername(peersock,&sockaddr,&addrsize);
  printf("peer address %s\n", inet_ntoa(sockaddr.sin_addr));

  close(peersock);
  };
};