客戶端底層 Socket 實現IPV4 IPV6網路環境的相容
先貼上蘋果給出的IPV6相關介紹的地址,很全面也比較詳細: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/
UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html
蘋果指出的IPV6是個什麼鬼呢?
實際上是指IPV6 DNS64/NAT64網路。IPV4和IPV6本就是兩個不同的協議,是不相容的。而V6又不可能立刻完全取代V4,所以就需要過渡技術來讓兩者互通,DNS64/NAT64技術就是用來保證IPV6網路環境下的終端可以訪問IPV4網路環境下的資源(注意,是單向的)。
DNS64/NAT64又是什麼鬼呢?
實際上就是網路供應商在IPV6網路與IPV4網路之間架上DNS64/NAT64伺服器來負責一個協議轉換的工作。借蘋果給出的圖來形象的展示一下,如下圖,終端在IPV6環境可直接訪問IPV6環境下的伺服器,而訪問IPV4環境下的伺服器時則需要經過DNS64/NAT64伺服器來實現協議轉換。
我們可以使用 OS X 10.11及以上系統的雙網絡卡Mac(乙太網口+無線網絡卡)來自己搭建一個IPV6 DNS64/NAT64網路環境。原理依然借用蘋果的圖來形象的展示一下,如下圖,MAC電腦擔任DNS64/NAT64伺服器的角色,其共享的無線網路就是一個IPV6-only網路,終端連線該無線網後即處於IPV6環境。
具體的搭建步驟很簡單,網上搜索一大堆,連結就不貼了。
OK,轉入正題,看看客戶端相容V4 V6的socket用法。
IPV6 環境下客戶端 Socket 程式設計與 IPV4 的區別主要在 socket 、connect 兩個函式的使用上,其餘的 read、write 等函式的使用都與 IPV4 一樣。
socket() 的函式原型為 int socket(int domain, int type, int protocol),兩者的區別在第一個引數的使用上,IPV4 為 AF_INET,IPV6 為 AF_INET6。
connect() 的函式原型為 int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen),兩者的區別在第二個和第三個的使用上,尤其是第二個引數的結構體,而該結構體引數則需要使用函式 getaddrinfo() 來獲得,以實現相容。
getaddrinfo() 函式的資訊很容易查到,不多解釋,先貼上專案程式碼裁剪後deamon程式碼,程式碼詳細介紹請檢視註釋。
int getconnectsocket_tcp(const char * ip_str, uint32_t ip, const char * port_str, uint16_t port)
{
int fd4 = -1, fd6 = -1;
int ret;
struct addrinfo hits;
struct addrinfo * results, * aitmp;
char host[40], portstr[6];
//任意一個fd建立成功,都有機會成功連線伺服器
fd4 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
fd6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (fd4 == -1 && fd6 == -1){
printf("socket create error:%s\n", strerror(errno));
return -1;
}
//設定非阻塞
set_sock_nonblocking(fd4);
set_sock_nonblocking(fd6);
//初始化 getaddrinfo 所需引數 hits
memset((void *)&hits, 0, sizeof(hits));
hits.ai_family = AF_UNSPEC; //注意這裡不要指定協議,這樣getaddrinfo函式會根據網路環境返回得到的全部地址(包含ipv4和ipv6)
hits.ai_socktype = SOCK_STREAM;
hits.ai_protocol = 0;
hits.ai_flags = 0;
//獲取伺服器的地址和埠的字串,域名IP均可
if(ip_str != NULL){
memcpy(host, ip_str, sizeof(host));
}else{
snprintf(host, sizeof(host), "%d", ip);
}
if(port_str != NULL){
memcpy(portstr, port_str, sizeof(portstr));
}else{
snprintf(portstr, sizeof(portstr), "%d", port);
}
//呼叫getaddrinfo函式來獲取伺服器的IP地址,結果存放在以第四個引數results為首地址的連結串列中
//需要注意的是:只有IOS9.2和OS X 10.11.2及以上系統支援IPV6地址的合成,即第一個引數host傳入IPV4地址,也能得到對應的IPV6地址
// IOS9.2和OS X 10.11.2以下系統只有第一個引數傳入域名時才能得到IPV6地址,若傳入IPV4地址則只能得到IPV4地址
ret = getaddrinfo(host, portstr, &hits, &results);
if(ret != 0){
printf("getaddrinfo error:%s\n", strerror(errno));
return -2;
}
//results連結串列中會存在ipv4和ipv6地址,所以遍歷該連結串列,當有一個connect成功時即可結束遍歷直接返回
//注意兩個connect第二個引數雖然都是aitmp->ai_addr,卻指的不同的結構體,第三個引數應該傳入對應結構體的大小
for(aitmp = results; aitmp != NULL; aitmp = aitmp->ai_next){
switch(aitmp->ai_family){
case AF_INET:
ret = connect(fd4, aitmp->ai_addr, sizeof(struct sockaddr_in));
if(ret == 0 || errno == EINPROGRESS || errno == EWOULDBLOCK){
if(fd6 >= 0)
close(fd6);
return fd4;
}
printf("IPV4 connect error:%s\n", strerror(errno));
break;
case AF_INET6:
ret = connect(fd6, aitmp->ai_addr, sizeof(struct sockaddr_in6));
if(ret == 0 || errno == EINPROGRESS || errno == EWOULDBLOCK){
if(fd4 >= 0)
close(fd4);
return fd6;
}
printf("IPV6 connect error:%s\n", strerror(errno));
break;
}
}
printf("connect fail!\n");
if(fd4 >= 0)
close(fd4);
if(fd6 >= 0)
close(fd6);
return -3;
}
connect成功以後其他操作都無需改變,所以IPV4 IPV6環境的相容其實就這麼簡單。
簡單提一下,其中 getaddrinfo 函式實際上就是前往上文提到的DNS64伺服器來獲取IP地址(特殊一點的DNS解析)。依然借用蘋果的圖,原理如下圖:
需要注意的是程式設計中會涉及到幾個結構體的相互關係(sockaddr、sockaddr_in、sockaddr_in6等)。(其中sockaddr *比較迷惑人,而實際上把這裡sockaddr * 理解成void *後,很多問題就明瞭了)
幾個結構體的資訊可以參考以下兩個地址:
http://blog.csdn.net/an_zhenwei/article/details/8591115
http://xyliufeng.iteye.com/blog/718862
除文中提到得連結,本文額外參考地址:
http://www.jianshu.com/p/a6bab07c4062
相關推薦
客戶端底層 Socket 實現IPV4 IPV6網路環境的相容
先貼上蘋果給出的IPV6相關介紹的地址,很全面也比較詳細: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOvervi
JAVA SOCKET網路程式設計,服務端接收多個客戶端連線的實現
這是基於前面一篇文章的一個簡單擴充套件,當然這不是最好的實現 服務端如果要想接收多個客戶端連線,必須死迴圈去接收新的客戶端的連線請求,一個完整的客戶端服務端socket連線通過一個執行緒來維護 package com.tree.demo.socket; import
高效能網路通訊框架Netty-Netty客戶端底層與Java NIO對應關係
5.1 Netty客戶端底層與Java NIO對應關係 在講解Netty客戶端程式時候我們提到指定NioSocketChannel用於建立客戶端NIO套接字通道的例項,下面我們來看NioSocketChannel是如何建立一個Java NIO裡面的SocketChannel的。 首先我們來看
在Android上實現SSL握手,實現伺服器和客戶端之間Socket互動
public class MySSLSocket extends Activity { private static final int SERVER_PORT = 50030;//埠號 private static final String SERVER_IP = "218.206.17
Linux----網路程式設計(TCP網路通訊客戶端伺服器程式設計實現多程序)
1、伺服器ser.c 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <assert.h> 5 #in
java在線聊天項目1.2版 ——開啟多個客戶端,分別實現數據庫註冊和登錄功能後,成功登陸則登錄框消失,好友列表窗出現
false als blog string def iat ets cat med 登錄框消失語句 dispose(); 好友列表窗出現 使用new FriendsFrame(phone,s); 登陸對話框代碼修改如下: package com.swift.frame;
OpenLDAP客戶端配置,實現用戶認證(原創)
pen img sss fuse sys src file 由於 onf 1.工作過程 OpenLDAP服務分為客戶端和服務端兩個部分,服務端的配置過程這裏不再贅述。當服務端配置結束後,在服務端的ldap數據庫中,應存放著用戶的信息,客戶端通過安裝nss-p
IdentityServer4客戶端JWT解密實現(基於.net4.0)
空字符串 token true iba localhost urn 代碼 github substr 情景:公司項目基於.net4.0,web客戶端實現單點登錄需要自己解密id_token,對於jwt解密,.net提供了IdentityModel類庫,但是4.0中該類庫不可
Python每日進階--如何在客戶端使用socket
Python 提供了兩個級別訪問的網路服務。: 低級別的網路服務支援基本的 Socket,它提供了標準的 BSD Sockets API,可以訪問底層作業系統Socket介面的全部方法。 高級別的網路服務模組 SocketServer, 它提供了伺服器中心類,可以簡化網
搭建FTP伺服器與客戶端(1) - Python實現
FTP背景介紹:FTP(File Transfer Protocol)協議,顧名思義為檔案傳輸協議。由已故的Jon Postel與Joyce Reynolds開發,並於1985年10月釋出。其底層基於TCP/IP協議。FTP目前主要用於匿名下載公共檔案,也可以在兩臺跨系統的計算機之間傳輸檔案。為了實現F
MQTT Java客戶端Eclipse paho實現資料的傳送和接收
MQTT(MQ Telemetry Transport)是IBM開發的一種網路應用層的協議 使用場景: 1、不可靠、網路頻寬小的網路 2、執行的裝置CPU、記憶體非常有限 特點: 1、基於釋出/訂閱模型的協議 2、他是二進位制協議,二進位制的特點就是緊湊、佔用
Ribbon使用及其客戶端負載均衡實現原理分析
1、ribbon負載均衡測試 (1)consumer工程新增依賴 <dependency> <groupId>org.springframework.cloud</groupId> <artif
【微信小程式控制硬體②】 開始微信小程式之旅,匯入小程式Mqtt客戶端原始碼,實現簡單的驗證和通訊於伺服器!(附帶原始碼)
本博文由熱愛分享熱愛技術的半顆心臟原創,非官方人員、非組織名義編寫,博文如有不對或侵犯您的權益,請及時留言,第一時間糾正! 一、前言; 繼續我們的小程式控制智慧硬體(包括esp8266)學
WebService客戶端幾種實現方式
一、釋出一個webservice服務。 /** * * 基於soap的服務 */ @WebService(name = "Login",// 定義Port名稱 serviceName = "MyService", // 修改WebService服務名稱 targetNamespa
web本地客戶端快取圖片實現
瀏覽器快取是提高使用者體驗和提升程式效能的一個很重要的途徑,通過瀏覽器的快取控制,可以對實時性要求不高的資料進行快取,可以減少甚至不需要再次對伺服器的請求就可以顯示資料。 本文將介紹如果通過HTTP協議中的header來控制瀏覽器的快取行為,建議大家在看的時候寫程式碼試驗下,這樣對這些header的理解
客戶端骨架屏實現
一直以來,無論是Web還是iOS、Android的應用中,為了提升應用的載入等待這段時間的使用者感知體驗,各種技術層出不窮。其中,尤以菊花圖以及由它衍生各種載入動畫最為突出。 對於菊花圖我們自不必多說,現在對於載入的設計體驗有了比菊花載入體驗更棒的方法,即大家常看到的Skeleton Screen Load
ftp客戶端的簡單實現
根據ftp協議實現簡單版的ftp客戶端與ftp伺服器進行互傳檔案 由於業務需要使用FTP伺服器進行檔案傳輸,因為一些因素的限制,需要自己實現一個ftp的客戶端與ftp伺服器進行檔案傳輸的任務, 利用抓包工具對ftp協議進行分析,實現了一個簡單的ftp客戶端 實驗環境
Python TCP 客戶端(配合socket多執行緒伺服器)
''' Python TCP 客戶端(配合socket多執行緒伺服器) by 鄭瑞國 1、建立網路套接字c 2、建立網路連線 3、收發資訊 ''' import socket c = socket.socket() #1、建立網路套接字c c.connect(('127.
Android手機客戶端通過JSP實現與Tomcat伺服器端通訊(Msql資料庫,Json作為載體)--服務端程式碼
伺服器端主要程式碼: 1.首先構建一個Person類,用來儲存使用者資訊 public class Person private String name; private String address; private Integer age; public P
Android:新浪微博拉起客戶端分享——完美實現同時分享圖片和文字(Intent.ACTION_SEND)
新浪微博拉起客戶端分享——完美實現同時分享圖片和文字(Intent.ACTION_SEND) 點選事件後處理: private void share(String content, Uri uri){