日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

getsockname函数与getpeername函数的使用

發布時間:2023/11/30 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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);//獲取connfd表示的連接上的本地地址??
  • ????????printf("connected?server?address?=?%s:%d\n",?inet_ntoa(connectedAddr.sin_addr),?ntohs(connectedAddr.sin_port));??
  • ????????getpeername(connfd,?(struct?sockaddr?*)&peerAddr,?&peerLen);?//獲取connfd表示的連接上的對端地址??
  • ????????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];//保存點分十進制的ip地址??
  • ??????
  • ????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);//獲取sockfd表示的連接上的本地地址??
  • ???
  • ????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函数的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。