這篇文章主要介紹了linux socket通訊獲取本地的源端口號的相關資料,需要的朋友可以參考下
關于TCP IP網絡通訊的資料非常多,TCP IP通過IP數據包模式進行端對端通訊。典型的TCP數據包如下
可以看到數據包包含了源端口號和目的端口號,客戶端socket向服務端發起連接時,系統會給socket隨機分配一個源端口號,我們可以通過getsocketname來獲取連接成功的socket的原端口信息。
函數原型
#include?<sys>? int?getsockname(int?sockfd,?struct?sockaddr?*addr,?socklen_t?*addrlen);</sys>
參數:
sockfd socket連接的句柄
addr 網絡地址指針,用來存儲本地端socket地址信息,
addrlen addr的空間大小
返回結果,如果調用成功,返回0,并將本地網絡地址信息存放在addr里面,失敗返回-1,并通過errno反應錯誤信息。
source_port.cpp
#include?<cstring>? #include?<cstdio>? #include?<cstdlib>? #include?<sys>? #include?<sys>? #include?<netinet>? #include?<netinet>? #include?<netdb.h>? #include?<errno.h>? #include?<unistd.h>? #include?<arpa>? void?safe_close(int?&sock);? int?main(int?argc,?char?*argv[])?{? ?int?sockfd?=?0,?n?=?0;? ?socklen_t?len?=?0;? ?char?host[512]?=?{0};? ?char?buf[1024]?=?{0};? ?struct?hostent?*server;? ?struct?sockaddr_in?serv_addr,?loc_addr;? ?if?(argc?h_addr,?server->h_length);? ?if?(-1?==?inet_pton(AF_INET,?host,?&serv_addr.sin_addr))?{? ??memset(buf,?0,?sizeof(buf));? ??snprintf(buf,?sizeof(buf),?"inet_pton?failed.?errno:?%d,?error:?%s",?errno,?strerror(errno));? ??perror(buf);? ??exit(-1);? ?}? ?if?(-1?==?connect(sockfd,?(struct?sockaddr?*)&serv_addr,?sizeof(serv_addr)))?{//?連接socket? ??memset(buf,?0,?sizeof(buf));? ??snprintf(buf,?sizeof(buf),?"connect?socket?failed.?errno:?%d,?error:?%s",?errno,?strerror(errno));? ??perror(buf);? ??exit(-1);? ?}? ?printf("connect?to?%s?success.n",?host);? ?len?=?sizeof(sizeof(loc_addr));? ?memset(&loc_addr,?0,?len);? ?if?(-1?==?getsockname(sockfd,?(struct?sockaddr?*)&loc_addr,?&len))?{//?獲取socket綁定的本地address信息? ??memset(buf,?0,?sizeof(buf));? ??snprintf(buf,?sizeof(buf),?"get?socket?name?failed.?errno:?%d,?error:?%s",?errno,?strerror(errno));? ??perror(buf);? ??safe_close(sockfd);? ??exit(-1);? ?}? ?if?(loc_addr.sin_family?==?AF_INET)?{//?打印信息? ??printf("local?port:?%un",?ntohs(loc_addr.sin_port));? ?}? ?safe_close(sockfd);? ?return?0;? }? void?safe_close(int?&sock)?{? ?if?(-1?!=?sock)?{? ??shutdown(sock,?SHUT_RDWR);? ??sock?=?-1;? ?}? }</arpa></unistd.h></errno.h></netdb.h></netinet></netinet></sys></sys></cstdlib></cstdio></cstring>
本程序首先會啟動一個socket連接一個普通的http服務器(baidu,qq,163,csdn),當socket連通時就通過getsocketname獲取連接綁定的本地地址,并通過該地址獲取源端口號。
終端1: 編譯及運行
$?g++?source_port.cpp $?./a.out?www.baidu.com connect?to?www.baidu.com?success. local?port:?39702
終端2: 通過tcpdump抓包驗證
$?sudo?tcpdump?host?www.baidu.com?-v tcpdump:?listening?on?eth0,?link-type?EN10MB?(Ethernet),?capture?size?65535?bytes 18:38:32.381448?IP?(tos?0x0,?ttl?64,?id?35033,?offset?0,?flags?[DF],?proto?TCP?(6),?length?60) icentos.39702?>?220.181.111.188.http:?Flags?[S],?cksum?0x8cd2?(incorrect?->?0x596a),?seq?2381397554,?win?29200,?options?[mss?1460,sackOK,TS?val?3513497323?ecr?0,nop,wscale?7],?length?0 18:38:32.425904?IP?(tos?0x0,?ttl?55,?id?35033,?offset?0,?flags?[DF],?proto?TCP?(6),?length?60) 220.181.111.188.http?>?icentos.39702:?Flags?[S.],?cksum?0xc315?(correct),?seq?3561856904,?ack?2381397555,?win?8192,?options?[mss?1424,sackOK,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,nop,wscale?5],?length?0 18:38:32.425930?IP?(tos?0x0,?ttl?64,?id?35034,?offset?0,?flags?[DF],?proto?TCP?(6),?length?40)
對比終端一和終端二表明獲取的源端口地址是正確的。
總結
? 版權聲明
文章版權歸作者所有,未經允許請勿轉載。
THE END