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