getsockname与getpeername用法与区别
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)。
總結
以上是生活随笔為你收集整理的getsockname与getpeername用法与区别的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sockaddr与sockaddr_in
- 下一篇: 零字节WSASend,WSARecv