在两台计算机上建立一个网络连接,需要五个要素:本机地址 本机端口 协议类型 远端端口 远端地址.那么如何从一个建立好的连接上获取这些信息呢.就需要用到
getsockname 和 getpeername 这两个函数.
但前提是要在建立好的连接上.
作为客户端,要在正确调用connect()之后,才能使用这两个函数
作为服务端,要在正确调用accept()之后,才能使用这两个函数
以下为测试代码, windows/linux 下均可编译运行.
#include <stdint.h> #include <stdio.h> #include <memory.h> #ifdef WIN32 #include <windows.h> typedef int32_t socklen_t; #define close(x) closesocket(x) #else #include <errno.h> #include <arpa/inet.h> #include <unistd.h> #define INVALID_SOCKET (-1) typedef int32_t SOCKET; #endif int32_t Errno() { #ifdef WIN32 return WSAGetLastError(); #else return errno; #endif } void test_getname(SOCKET sock, const char *desc) { printf("%s ", desc); struct sockaddr_in addr; socklen_t addr_len = sizeof(addr); int32_t ret = getsockname(sock, (struct sockaddr *)&addr, &addr_len); if(ret == 0) { printf("getsockname succ:%s:%d ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } else { printf("getsockname failed,error=%d ", Errno()); } memset(&addr, 0, sizeof(addr)); ret = getpeername(sock, (struct sockaddr *)&addr, &addr_len); if(ret == 0) { printf("getpeername succ:%s:%d ", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } else { printf("getpeername failed,error=%d ", Errno()); } } void test_connect() { sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(5000); SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); test_getname(sock, "before connect"); int32_t ret = connect(sock, (sockaddr*)&addr, sizeof(addr)); if(ret != 0) { printf("connect error, errno: %d ", Errno()); return; } test_getname(sock, "after connect"); close(sock); } void test_accept() { SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(INVALID_SOCKET == sock) { printf("create socket error,errno=%d ", Errno()); return; } sockaddr_in srvAddr; memset(&srvAddr, 0, sizeof(srvAddr)); srvAddr.sin_family = AF_INET; srvAddr.sin_addr.s_addr = htonl(INADDR_ANY); srvAddr.sin_port = htons(5000); test_getname(sock, "before bind"); int32_t ret = bind(sock, (sockaddr*)&srvAddr, sizeof(srvAddr)); printf("bind:%s:%d ", inet_ntoa(srvAddr.sin_addr), ntohs(srvAddr.sin_port)); test_getname(sock, "after bind"); if(ret != 0) { printf("bind listen socket error,errno=%d ", Errno()); return; } ret = listen(sock, SOMAXCONN); if(ret != 0) { return; } sockaddr_in cliAddr; socklen_t cliAddrLen = sizeof(cliAddr); SOCKET new_sock = accept(sock, (sockaddr*)&cliAddr, &cliAddrLen); printf("accept:%s:%d ", inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port)); test_getname(new_sock, "after accept"); close(sock); close(new_sock); } int32_t main() { #ifdef WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); #endif //test_connect(); test_accept(); #ifdef WIN32 WSACleanup(); #endif getchar(); return 0; }
测试结果:
connect:
before connect getsockname failed,error=10022 getpeername failed,error=10057 after connect getsockname succ:127.0.0.1:4618 getpeername succ:127.0.0.1:5000
accept:
before bind getsockname failed,error=10022 getpeername failed,error=10057 bind:0.0.0.0:5000 after bind getsockname succ:0.0.0.0:5000 getpeername failed,error=10057 accept:127.0.0.1:4630 after accept getsockname succ:127.0.0.1:5000 getpeername succ:127.0.0.1:4630