int getsockname(int sockfd, struct sockaddr * localaddr, socken_t * addrlen);
int getpeername(int sockfd, struct sockaddr * peeraddr, socken_t * addrlen);
返回0表示成功,返回1表示出错
参数sockfd表示你要获取的套接口的描述字。
localaddr返回本地协议地址描述结构, peeraddr返回远程协议地址描述结构,addrlen分别是上述2个结构的长度。这个2个函数不难,下面是使用样例
#include <stdafx.h>
#include <stdio.h>
#include <windows.h>
#include <winsock.h>
#pragma comment(lib,"WS2_32");
int main()
{
WSAData tWSAData;
WSAStartup(MAKEWORD(2,2),&tWSAData);
SOCKET CreateSocket;
SOCKET AcceptSocket;
sockaddr_in sockaddr_in_server;
sockaddr_in sockaddr_in_client;
sockaddr_in_server.sin_port = htons(88);
sockaddr_in_server.sin_family = AF_INET;
sockaddr_in_server.sin_addr.S_un.S_addr = INADDR_ANY;//此程序在任何IP上面都可以运行
CreateSocket = socket(AF_INET,SOCK_STREAM,0);
int ret_bind = bind(CreateSocket,(struct sockaddr FAR *)&sockaddr_in_server,sizeof(sockaddr_in));
if (ret_bind != 0)
{
int WSAGLE = WSAGetLastError();//WSAEADDRINUSE 10048
return WSAGLE;
}
listen(CreateSocket,SOMAXCONN);
printf("等待客户端链接...\n");
int addrlen = sizeof(sockaddr_in);
AcceptSocket = accept(CreateSocket,(struct sockaddr FAR *)&sockaddr_in_client,&addrlen);
int send_data_size;
char buf[] = "这是来自服务器的send";
send_data_size = send(AcceptSocket,buf,sizeof(buf),0);
char bufrecv[30];
int recv_data_size=0;
recv_data_size = recv(AcceptSocket,bufrecv,MAX_PATH,0);
bufrecv[recv_data_size] = '\0';
printf("收到来自客户端的信息:%s\n",bufrecv);
while (strcmp(bufrecv,"exit")!=0 || recv_data_size==SOCKET_ERROR)
{
recv_data_size = recv(AcceptSocket,bufrecv,100,0);//默认是阻塞函数,如果一次send的数据大于一次recv的数据,recv将连续多次获取该数据
bufrecv[recv_data_size] = '\0';
printf("收到来自客户端的信息:%s\n",bufrecv);
sockaddr_in getsockaddr;
int len = sizeof(sockaddr_in);
int r=getsockname(CreateSocket,(sockaddr *)&getsockaddr,&len);
int port=ntohs(getsockaddr.sin_port);
int e = WSAGetLastError();
sockaddr_in getsockaddr2;
int len2 = sizeof(sockaddr_in);
int r2=getpeername(AcceptSocket,(sockaddr *)&getsockaddr2,&len2);
int port2=ntohs(getsockaddr2.sin_port);
int e2 = WSAGetLastError();
}
closesocket(AcceptSocket);
closesocket(CreateSocket);
WSACleanup();
return 0;
}
补充:
1.getsockname和getpeername调度时机很重要,如果调用时机不对,则无法正确获得地址和端口。
2.注意网络字节序和本地字节序
TCP
对于服务器来说,在bind以后就可以调用getsockname来获取本地地址和端口,虽然这没有什么太多的意义。getpeername只有在链接建立以后才调用,否则不能正确获得对方地址和端口,所以他的参数描述字一般是链接描述字而非监听套接口描述字。
对于客户端来说,在调用socket时候内核还不会分配IP和端口,此时调用getsockname不会获得正确的端口和地址(当然链接没建立更不可能调用getpeername),当然如果调用了bind 以后可以使用getsockname。想要正确的到对方地址(一般客户端不需要这个功能),则必须在链接建立以后,同样链接建立以后,此时客户端地址和端口就已经被指定,此时是调用getsockname的时机。
UDP
UDP分为链接和没有链接2种(这个到UDP与connect可以找到相关内容)
没有链接的UDP不能调用getpeername,但是可以调用getsockname,和TCP一样,他的地址和端口不是在调用socket就指定了,而是在第一次调用sendto函数以后
已经链接的UDP,在调用connect以后,这2个函数都是可以用的(同样,getpeername也没太大意义。如果你不知道对方的地址和端口,不可能会调用connect)。