生活随笔
收集整理的這篇文章主要介紹了
getsockname函数与getpeername函数的使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
https://www.tuicool.com/articles/V3Avey
getsockname和getpeername函數
getsockname函數用于獲取與某個套接字關聯的本地協議地址?
getpeername函數用于獲取與某個套接字關聯的外地協議地址
定義如下:
[cpp]?view plaincopy
#include<sys/socket.h>????int?getsockname(int?sockfd,?struct?sockaddr?*localaddr,?socklen_t?*addrlen);????int?getpeername(int?sockfd,?struct?sockaddr?*peeraddr,?socklen_t?*addrlen);??
對于這兩個函數,如果函數調用成功,則返回0,如果調用出錯,則返回-1。
使用這兩個函數,我們可以通過套接字描述符來獲取自己的IP地址和連接對端的IP地址,如在未調用bind函數的TCP客戶端程序上,可以通過調用getsockname()函數獲取由內核賦予該連接的本地IP地址和本地端口號,還可以在TCP的服務器端accept成功后,通過getpeername()函數來獲取當前連接的客戶端的IP地址和端口號。
如下面的客戶端-服務器程序:
服務器端代碼
[cpp]?view plaincopy
??#define?MAXLINE?4096??#define?PORT?6563??#define?LISTENQ?1024??#include<stdio.h>??#include<sys/socket.h>??#include<netinet/in.h>??#include<unistd.h>??#include<string.h>??#include<arpa/inet.h>????int?main()?{??????int?listenfd,?connfd;??????struct?sockaddr_in?servaddr;??????struct?sockaddr_in?listendAddr,?connectedAddr,?peerAddr;??????int?listendAddrLen,?connectedAddrLen,?peerLen;??????char?ipAddr[INET_ADDRSTRLEN];??????listenfd?=?socket(AF_INET,?SOCK_STREAM,?0);??????memset(&servaddr,?0,?sizeof(servaddr));????????servaddr.sin_family?=?AF_INET;??????servaddr.sin_addr.s_addr?=?htonl(INADDR_ANY);??????servaddr.sin_port?=?htons(PORT);????????????bind(listenfd,?(struct?sockaddr*)&servaddr,?sizeof(servaddr));????????listen(listenfd,?LISTENQ);??????listendAddrLen?=?sizeof(listendAddr);??????getsockname(listenfd,?(struct?sockaddr?*)&listendAddr,?&listendAddrLen);??????printf("listen?address?=?%s:%d\n",?inet_ntoa(listendAddr.sin_addr),?ntohs(listendAddr.sin_port));????????while(1)?{??????????connfd?=?accept(listenfd,?(struct?sockaddr?*)NULL,?NULL);??????????connectedAddrLen?=?sizeof(connectedAddr);??????????getsockname(connfd,?(struct?sockaddr?*)&connectedAddr,?&connectedAddrLen);??????????printf("connected?server?address?=?%s:%d\n",?inet_ntoa(connectedAddr.sin_addr),?ntohs(connectedAddr.sin_port));??????????getpeername(connfd,?(struct?sockaddr?*)&peerAddr,?&peerLen);???????????printf("connected?peer?address?=?%s:%d\n",?inet_ntop(AF_INET,?&peerAddr.sin_addr,?ipAddr,?sizeof(ipAddr)),?ntohs(peerAddr.sin_port));??????}??????return?0;??}??
上面的代碼中,在調用listen函數之后就獲取監聽套接字描述符對應的本地地址,在accept()函數后,由于accept返回了一個套接字描述符connfd用于表示該連接,所以可以對這個connfd調用getsockname函數和getpeername函數,分別獲取內核賦予該連接的本地IP地址和連接的對端地址。
客戶端代碼
[cpp]?view plaincopy
??#define?PORT?6563??#include<stdio.h>??#include<sys/socket.h>??#include<netinet/in.h>??#include<unistd.h>??#include<string.h>??#include<arpa/inet.h>????int?main(int?argc,?char?**argv)?{??????struct?sockaddr_in?servaddr;??????struct?sockaddr_in?clientAddr;??????int?sockfd;???????int?clientAddrLen?=?sizeof(clientAddr);??????char?ipAddress[INET_ADDRSTRLEN];????????????if(argc?<?2)?{??????????printf("parameter?error");??????}????????sockfd?=?socket(AF_INET,?SOCK_STREAM,?0);??????memset(&servaddr,?0,?sizeof(servaddr));??????servaddr.sin_family?=?AF_INET;??????servaddr.sin_port?=?htons(PORT);????????if(inet_pton(AF_INET,?argv[1],?&servaddr.sin_addr)?<=?0)?{??????????printf("server?address?error\n");??????}????????connect(sockfd,?(struct?sockaddr?*)&servaddr,?sizeof(servaddr));????????????getsockname(sockfd,?(struct?sockaddr*)&clientAddr,?&clientAddrLen);?????????printf("client:client?ddress?=?%s:%d\n",?inet_ntop(AF_INET,?&clientAddr.sin_addr,?ipAddress,?sizeof(ipAddress)),?ntohs(clientAddr.sin_port));??????return?0;??}??
在客戶端的代碼中,調用connect函數后,即可調用getsockname來獲連接上的本地地址。
代碼的運行結果如下:
服務區端輸出
客戶端輸出
從上面的代碼中可以看到,服務器端listenfd套接字描述符對應的地址即為綁定的通配IP地址和指定的端口,而connfd套接字描述符對應的連接的服務器端的地址為內核賦予的地址和用戶指定的端口。
上面的客戶端與服務器端的代碼中使用了函數inet_ntoa,inet_pton對32位的地址進行轉換,其中inet_ntoa是較老的函數,與它一起的還有函數inet_addr和inet_ntoa,這三個函數的定義如下:
[cpp]?view plaincopy
#include<arpa/inet.h>????int?inet_aton(const?char?*strptr,?struct?in_addr?*addrptr);????in_addr_t?inet_addr(const?char?*strptr);????char?*inet_ntoa(struct?in_addr?inaddr);??
inet_aton與inet_addr函數的功能類似,都是將點分十進制的字符串表示的IP地址轉換成32位的網絡字節序的IPv4地址。
inet_ntoa函數將32位的網絡字節序的IPv4地址轉換成點分十進制的字符串表示的IP地址,inet_addr函數已被廢棄,并且這三個函數只針對IPv4地址有效,在點分十進制數串和32位的網絡字節序二進制值間進行轉換,如果要對于IPv4和IPv6都適用,那么使用下面兩個函數:
[cpp]?view plaincopy
#include<arpa/inet.h>????int?inet_pton(int?family,?const?char?*strptr,?void?*addrptr);????const?char?*inet_ntop(int?family,?const?void?*addrptr,?char?*strptr,?size_t?len);??
函數中的p和n分別代表表達式(presentation)和數值(numeric)
所以inet_pton函數將strptr指針所指的字符串轉換為網絡地址(IPv4和IPv6),再將地址保存到addrptr指向的結構體中,inet_ntop將網絡地址轉為字符串表示的地址,結果存放在strptr中,len參數是strptr的大小。
這兩個函數支持IPv4和IPv6,所以需要通過參數family來指定,當前要轉換的是IPv4地址還是IPv6地址。
Reference
《UNIX網絡編程 卷1:套接字聯網API(第3版)》
總結
以上是生活随笔為你收集整理的getsockname函数与getpeername函数的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。