对于TCP服务器来说,如果设置的addr为INADDR_ANY,只有在accept后,用getsockname获得的者是本地分配的真实的ip,即针对已经连接的,而不是监听套接口。
用getpeername可以获取客户端的地址,虽然说,在accept时,就可以返回客户端的地址。但是当accept后,fork一个子进程,接着调用 exec时,会将返回客户地址覆盖,在这种情况下,用getpeername。
可以模拟,在windows上运行客户端程序:
#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#define MAXLINE 100
#pragma comment(lib, "ws2_32.lib")
void dlg_cli(int fd)
{
char buf[MAXLINE];
int n;
for (;;) {
if (fgets(buf, MAXLINE, stdin) != NULL) {
send(fd, buf, strlen(buf), 0);
n = recv(fd, buf, MAXLINE, 0);
if (n != 0) {
buf[n] = '\0';
puts(buf);
}
}
}
}
int main(int argc, char **argv)
{
WSADATA data;
WORD wVersionRequested;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &data);
if (err != 0) return -1;
if (LOBYTE(data.wVersion) != 1 || HIBYTE(data.wVersion) != 1) {
WSACleanup();
return -1;
}
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
SOCKADDR_IN addrSer;
addrSer.sin_family = AF_INET;
addrSer.sin_port = htons(9999);
printf("addr=%s\n", argv[1]);
addrSer.sin_addr.S_un.S_addr = inet_addr(argv[1]);
connect(sockClient, (SOCKADDR*)&addrSer, sizeof(addrSer));
dlg_cli(sockClient);
closesocket(sockClient);
WSACleanup();
return 0;
}
注意:windows下,要加#pragma comment(lib, "ws2_32.lib"),如果不加,会提示未定义的符号之类错误
而在虚拟机中的linux下运行服务器,在accept前和后,调用getsockname,打印其分配的地址。如果创建socket时,指定的是INADDR_ANY,在accept前打印的是0.0.0.0,在accept后打印的是真实的网络接口的地址。