iOS應用如何支持IPV6

本文轉自 http://www.code4app.com/forum.php?mod=viewthread&tid=8427&highlight=ipv6

果然是蘋果打個哈欠,iOS行業內就得起一次風暴呀。自從5月初Apple明文規定所有開發者在6月1號以后提交新版本需要支持IPV6-Only的網絡,大家便開始熱火朝天的研究如何支持IPV6,以及應用中哪些模塊目前不支持IPV6。

一、IPV6-Only支持是啥?

首先IPV6,是對IPV4地址空間的擴充。目前當我們用iOS設備連接上Wifi、4G、3G等網絡時,設備被分配的地址均是IPV4地址,但是隨著運營商和企業逐漸部署IPV6 DNS64/NAT64網絡之后,設備被分配的地址會變成IPV6的地址,而這些網絡就是所謂的IPV6-Only網絡,并且仍然可以通過此網絡去獲取IPV4地址提供的內容。客戶端向服務器端請求域名解析,首先通過DNS64 Server查詢IPv6的地址,如果查詢不到,再向DNS Server查詢IPv4地址,通過DNS64 Server合成一個IPV6的地址,最終將一個IPV6的地址返回給客戶端。如圖所示:
<ignore_js_op>?
NAT64-DNS64-ResolutionOfIPv4_2x.png


在Mac OS 10.11+的雙網卡的Mac機器(以太網口+無線網卡),我們可以通過模擬構建這么一個local IPv6 DNS64/NAT64 的網絡環境去測試應用是否支持IPV6-Only網絡,大概原理如下:
<ignore_js_op>?
local_ipv6_dns64_nat64_network_2x.png


  • 參考資料:
    • https://developer.apple.com/library/mac/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/UnderstandingandPreparingfortheIPv6Transition/UnderstandingandPreparingfortheIPv6Transition.html#//apple_ref/doc/uid/TP40010220-CH213-SW1



二、Apple如何審核支持IPV6-Only?

首先第一點:這里說的支持IPV6-Only網絡,其實就是說讓應用在 IPv6 DNS64/NAT64 網絡環境下仍然能夠正常運行。但是考慮到我們目前的實際網絡環境仍然是IPV4網絡,所以應用需要能夠同時保證IPV4和IPV6環境下的可用性。從這點來說,蘋果不會去掃描IPV4的專有API來拒絕審核通過,因為IPV4的API和IPV6的API調用都會同時存在于代碼中。


其次第二點:Apple官方聲明iOS9開始向IPV6支持過渡,在iOS9.2+支持IPV4地址合成IPV6地址。其提供的Reachability庫在iOS8系統下,當從IPV4切換到IPV6網絡,或者從IPV6網絡切換到IPV4,是無法監控到網絡狀態的變化。也有一些開發者針對這些Bug詢問Apple的審核部門,給予的答復是只需要在蘋果最新的系統上保證IPV6的兼容性即可
最后第三點:只要應用的主流程支持IPV6,通過蘋果審核即可。對于不支持IPV6的模塊,考慮到我們現實IPV6網絡的部署還需要一段時間,短時間內不會影響我們用戶的使用。但隨著4G網絡IPV6的部署,這部分模塊還是需要逐漸安排人力進行支持。




三、應用如何支持IPV6-Only?

對于如何支持IPV6-Only,官方給出了如下幾點標準:(這里就不對其進行解釋了,大家看上面的參考鏈接即可)

1. Use High-Level Networking Frameworks;2. Don’t Use IP Address Literals;3. Check Source Code for IPv6 DNS64/NAT64 Incompatibilities;4. Use System APIs to Synthesize IPv6 Addresses;3.1 NSURLConnection是否支持IPV6?

官方的這句話讓我們疑惑頓生:
using high-level networking APIs such as NSURLSession and the CFNetwork frameworks and you connect by name, you should not need to change anything for your app to work with IPv6 addresses
只說了NSURLSession和CFNetwork的API不需要改變,但是并沒有提及到NSURLConnection。 從上文的參考資料中,我們看到NSURLSession、NSURLConnection同屬于Cocoa的url loading system,可以猜測出NSURLConnection在ios9上是支持IPV6的。
應用里面的API網絡請求,大家一般都會選擇AFNetworking進行請求發送,由于歷史原因,應用的代碼基本上都深度引用了AFHTTPRequestOperation類,所以目前API網絡請求均需要通過NSURLConnection發送出去,所以必須確認NSURLConnection是否支持IPV6. 經過測試,NSURLConnection在最新的iOS9系統上是支持IPV6的。


3.2 Cocoa的URL Loading System從iOS哪個版本開始支持IPV6?

目前我們的應用最低版本還需要支持iOS7,雖然蘋果只要求最新版本支持IPV6-Only,但是出于對用戶負責的態度,我們仍然需要搞清楚在低版本上URL Loading System的API是否支持IPV6.
(to fix me, make some experiments)待續~~~


3.3 Reachability是否需要修改支持IPV6?

我們可以查到應用中大量使用了Reachability進行網絡狀態判斷,但是在里面卻使用了IPV4的專用API。
[Objective-C]?查看源文件?復制代碼
?
1
2
3
在Pods:Reachability中
AF_INET????????????????? Files:Reachability.m
struct sockaddr_in?????? Files:Reachability.h , Reachability.m




那Reachability應該如何支持IPV6呢?
(1)目前Github的開源庫Reachability的最新版本是3.2,蘋果也出了一個Support IPV6 的Reachability的官方樣例,我們比較了一下源碼,跟Github上的Reachability沒有什么差異。
(2)我們通常都是通過一個0.0.0.0 (ZeroAddress)去開啟網絡狀態監控,經過我們測試,在iOS9以上的系統上IPV4和IPV6網絡環境均能夠正常使用;但是在iOS8上IPV4和IPV6相互切換的時候無法監控到網絡狀態的變化,可能是因為蘋果在iOS8上還并沒有對IPV6進行相關支持相關。(但是這仍然滿足蘋果要求在最新系統版本上支持IPV6的網絡)。

(3)當大家都在要求Reachability添加對于IPV6的支持,其實蘋果在iOS9以上對Zero Address進行了特別處理,官方發言是這樣的:

reachabilityForInternetConnection: This monitors the address 0.0.0.0,
which reachability treats as a special token that causes it to actually
monitor the general routing status of the device, both IPv4 and IPv6.

?

[Objective-C]?查看源文件?復制代碼
?
1
2
3
4
5
6
7
+ (instancetype)reachabilityForInternetConnection {
????struct sockaddr_in zeroAddress;
????bzero(&zeroAddress, sizeof(zeroAddress));
????zeroAddress.sin_len = sizeof(zeroAddress);
????zeroAddress.sin_family = AF_INET;
????return [self reachabilityWithAddress: (const struct sockaddr *) &zeroAddress];
}




綜上所述,Reachability不需要做任何修改,在iOS9上就可以支持IPV6和IPV4,但是在iOS9以下會存在bug,但是蘋果審核并不關心。



四、底層的socket API如何同時支持IPV4和IPV6?

由于在應用中使用了網絡診斷的組件,大量使用了底層的 socket API,所以對于IPV6支持,這塊是個重頭戲。如果你的應用中使用了長連接,其必然會使用底層socket API,這一塊也是需要支持IPV6的。 對于Socket如何同時支持IPV4和IPV6,可以參考谷歌的開源庫CocoaAsyncSocket.


下面我針對我們的開源?網絡診斷組件, 說一下是如何同時支持IPV4和IPV6的。
開源地址:https://github.com/Lede-Inc/LDNetDiagnoService_IOS.git

這個網絡診斷組件的主要功能如下:
  • 本地網絡環境的監測(本機IP+本地網關+本地DNS+域名解析);
  • 通過TCP Connect監測到域名的連通性;
  • 通過Ping 監測到目標主機的連通耗時;
  • 通過traceRoute監測設備到目標主機中間每一個路由器節點的ICMP耗時;





4.1 IP地址從二進制到符號的轉化

之前我們都是通過inet_ntoa()進行二進制到符號,這個API只能轉化IPV4地址。而inet_ntop()能夠兼容轉化IPV4和IPV6地址。 寫了一個公用的in6_addr的轉化方法如下:
[Objective-C]?查看源文件?復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//for IPV6
+(NSString *)formatIPV6Address:(struct in6_addr)ipv6Addr{
????NSString *address = nil;
????char dstStr[INET6_ADDRSTRLEN];
????char srcStr[INET6_ADDRSTRLEN];
????memcpy(srcStr, &ipv6Addr, sizeof(struct in6_addr));
????if(inet_ntop(AF_INET6, srcStr, dstStr, INET6_ADDRSTRLEN) != NULL){
????????address = [NSString stringWithUTF8String:dstStr];
????}
????return address;
}
//for IPV4
+(NSString *)formatIPV4Address:(struct in_addr)ipv4Addr{
????NSString *address = nil;
????char dstStr[INET_ADDRSTRLEN];
????char srcStr[INET_ADDRSTRLEN];
????memcpy(srcStr, &ipv4Addr, sizeof(struct in_addr));
????if(inet_ntop(AF_INET, srcStr, dstStr, INET_ADDRSTRLEN) != NULL){
????????address = [NSString stringWithUTF8String:dstStr];
????}
????return address;
}





4.2 本機IP獲取支持IPV6

相當于我們在終端中輸入ifconfig命令獲取字符串,然后對ifconfig結果字符串進行解析,獲取其中en0(Wifi)、pdp_ip0(移動網絡)的ip地址。
注意:
(1)在模擬器和真機上都會出現以FE80開頭的IPV6單播地址影響我們判斷,所以在這里進行特殊的處理(當第一次遇到不是單播地址的IP地址即為本機IP地址)。
(2)在IPV6環境下,真機測試的時候,第一個出現的是一個IPV4地址,所以在IPV4條件下第一次遇到單播地址不退出。
[Objective-C]?查看源文件?復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+ (NSString *)deviceIPAdress
{
????????while (temp_addr != NULL) {
????????????NSLog(@"ifa_name===%@",[NSString stringWithUTF8String:temp_addr->ifa_name]);
????????????// Check if interface is en0 which is the wifi connection on the iPhone
????????????if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"] || [[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"pdp_ip0"])
????????????{
????????????????//如果是IPV4地址,直接轉化
????????????????if (temp_addr->ifa_addr->sa_family == AF_INET){
????????????????????// Get NSString from C String
???????????????????address = [self formatIPV4Address:((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr];
????????????????}
????????????????//如果是IPV6地址
????????????????else if (temp_addr->ifa_addr->sa_family == AF_INET6){
????????????????????address = [self formatIPV6Address:((struct sockaddr_in6 *)temp_addr->ifa_addr)->sin6_addr];
????????????????????if (address && ![address isEqualToString:@""] && ![address.uppercaseString hasPrefix:@"FE80"]) break;
????????????????}
????????????}
????????????temp_addr = temp_addr->ifa_next;
????????}
????}
}





4.3 設備網關地址獲取獲取支持IPV6

其實是在IPV4獲取網關地址的源碼的基礎上進行了修改,初開把AF_INET->AF_INET6, sockaddr -> sockaddr_in6之外,還需要注意如下修改,就是拷貝的地址字節數。去掉了ROUNDUP的處理。 (解析出來的地址老是少了4個字節,結果是偏移量搞錯了,糾結了半天),具體參考源碼庫。
[Objective-C]?查看源文件?復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* net.route.0.inet.flags.gateway */
??int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET6, NET_RT_FLAGS, RTF_GATEWAY};
??if (sysctl(mib, sizeof(mib) / sizeof(int), buf, &l, 0, 0) < 0) {
???????address = @"192.168.0.1";
??}
??....
??//for IPV4
??for (i = 0; i < RTAX_MAX; i++) {
??????????????if (rt->rtm_addrs & (1 << i)) {
??????????????????sa_tab[i] = sa;
??????????????????sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len));
??????????????} else {
??????????????????sa_tab[i] = NULL;
??????????????}
??????????}
//for IPV6
???for (i = 0; i < RTAX_MAX; i++) {
??????????????if (rt->rtm_addrs & (1 << i)) {
??????????????????sa_tab[i] = sa;
??????????????????sa = (struct sockaddr_in6 *)((char *)sa + sa->sin6_len);
??????????????} else {
??????????????????sa_tab[i] = NULL;
??????????????}
??????????}







4.4 設備DNS地址獲取支持IPV6

IPV4時只需要通過res_ninit進行初始化就可以獲取,但是在IPV6環境下需要通過res_getservers()接口才能獲取。

?

[Objective-C]?查看源文件?復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
+(NSArray *)outPutDNSServers{
????res_state res = malloc(sizeof(struct __res_state));
????int result = res_ninit(res);
????NSMutableArray *servers = [[NSMutableArray alloc] init];
????if (result == 0) {
????????union res_9_sockaddr_union *addr_union = malloc(res->nscount * sizeof(union res_9_sockaddr_union));
????????res_getservers(res, addr_union, res->nscount);
????????for (int i = 0; i < res->nscount; i++) {
????????????if (addr_union[i].sin.sin_family == AF_INET) {
????????????????char ip[INET_ADDRSTRLEN];
????????????????inet_ntop(AF_INET, &(addr_union[i].sin.sin_addr), ip, INET_ADDRSTRLEN);
????????????????NSString *dnsIP = [NSString stringWithUTF8String:ip];
????????????????[servers addObject:dnsIP];
????????????????NSLog(@"IPv4 DNS IP: %@", dnsIP);
????????????} else if (addr_union[i].sin6.sin6_family == AF_INET6) {
????????????????char ip[INET6_ADDRSTRLEN];
????????????????inet_ntop(AF_INET6, &(addr_union[i].sin6.sin6_addr), ip, INET6_ADDRSTRLEN);
????????????????NSString *dnsIP = [NSString stringWithUTF8String:ip];
????????????????[servers addObject:dnsIP];
????????????????NSLog(@"IPv6 DNS IP: %@", dnsIP);
????????????} else {
????????????????NSLog(@"Undefined family.");
????????????}
????????}
????}
????res_nclose(res);
????free(res);
????return [NSArray arrayWithArray:servers];
}




4.4 域名DNS地址獲取支持IPV6

在IPV4網絡下我們通過gethostname獲取,而在IPV6環境下,通過新的gethostbyname2函數獲取。
[Objective-C]?查看源文件?復制代碼
?
1
2
3
4
5
//ipv4
phot = gethostbyname(hostN);
//ipv6
?phot = gethostbyname2(hostN, AF_INET6);





4.5 ping方案支持IPV6

Apple的官方提供了最新的支持IPV6的ping方案,參考地址如下:
https://developer.apple.com/library/mac/samplecode/SimplePing/Introduction/Intro.html
只是需要注意的是:
(1)返回的packet去掉了IPHeader部分,IPV6的header部分也不返回TTL(Time to Live)字段;
(2)IPV6的ICMP報文不進行checkSum的處理;



4.6 traceRoute方案支持IPV6

其實是通過創建socket套接字模擬ICMP報文的發送,以計算耗時;
兩個關鍵的地方需要注意:
(1)IPV6中去掉IP_TTL字段,改用跳數IPV6_UNICAST_HOPS來表示;
(2)sendto方法可以兼容支持IPV4和IPV6,但是需要最后一個參數,制定目標IP地址的大小;因為前一個參數只是指明了IP地址的開始地址。千萬不要用統一的sizeof(struct sockaddr), 因為sockaddr_in 和 sockaddr都是16個字節,兩者可以通用,但是sockaddr_in6的數據結構是28個字節,如果不顯式指定,sendto方法就會一直返回-1,erroNo報22 Invalid argument的錯誤。


關鍵代碼如下:(完整代碼參考開源組件)
[Objective-C]?查看源文件?復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//構造通用的IP地址結構stuck sockaddr
?NSString *ipAddr0 = [serverDNSs objectAtIndex:0];
????//設置server主機的套接口地址
????NSData *addrData = nil;
????BOOL isIPV6 = NO;
????if ([ipAddr0 rangeOfString:@":"].location == NSNotFound) {
????????isIPV6 = NO;
????????struct sockaddr_in nativeAddr4;
????????memset(&nativeAddr4, 0, sizeof(nativeAddr4));
????????nativeAddr4.sin_len = sizeof(nativeAddr4);
????????nativeAddr4.sin_family = AF_INET;
????????nativeAddr4.sin_port = htons(udpPort);
????????inet_pton(AF_INET, ipAddr0.UTF8String, &nativeAddr4.sin_addr.s_addr);
????????addrData = [NSData dataWithBytes:&nativeAddr4 length:sizeof(nativeAddr4)];
????} else {
????????isIPV6 = YES;
????????struct sockaddr_in6 nativeAddr6;
????????memset(&nativeAddr6, 0, sizeof(nativeAddr6));
????????nativeAddr6.sin6_len = sizeof(nativeAddr6);
????????nativeAddr6.sin6_family = AF_INET6;
????????nativeAddr6.sin6_port = htons(udpPort);
????????inet_pton(AF_INET6, ipAddr0.UTF8String, &nativeAddr6.sin6_addr);
????????addrData = [NSData dataWithBytes:&nativeAddr6 length:sizeof(nativeAddr6)];
????}
????struct sockaddr *destination;
????destination = (struct sockaddr *)[addrData bytes];
//創建socket
if ((recv_sock = socket(destination->sa_family, SOCK_DGRAM, isIPV6?IPPROTO_ICMPV6:IPPROTO_ICMP)) < 0)
if ((send_sock = socket(destination->sa_family, SOCK_DGRAM, 0)) < 0)
//設置sender 套接字的ttl
if ((isIPV6?
setsockopt(send_sock,IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)):
setsockopt(send_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl))) < 0)
//發送成功返回值等于發送消息的長度
ssize_t sentLen = sendto(send_sock, cmsg, sizeof(cmsg), 0,
(struct sockaddr *)destination,
isIPV6?sizeof(struct sockaddr_in6):sizeof(struct sockaddr_in));



轉載于:https://www.cnblogs.com/idxdm/p/5553423.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457827.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457827.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457827.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SQL Server -- SQLserver 存儲過程執行錯誤記錄到表

SQLserver 存儲過程執行錯誤記錄到表 From: http://blog.csdn.net/leshami/article/details/51333650 對于在執行存儲過程中碰到的一些錯誤&#xff0c;如果未及時捕獲或者說傳遞給前端應用程序來&#xff0c;在這樣的情形下&#xff0c;故障的排查顯得尤為困難。基于此&…

opencv python教程簡書_OpenCV-Python系列二:常用的圖像屬性

對于圖像&#xff0c;我們經常需要知道關于圖像的特殊屬性&#xff0c;比如寬度&#xff0c;高度&#xff0c;面積&#xff0c;像素點數目等等&#xff0c;那么在opencv-python中&#xff0c;這些信息如何獲取呢&#xff1f; 本文結構&#xff1a; 1.基本圖像屬性 2. 對于openc…

C++靜態成員函數指針

C的靜態成員函數指針 先簡單的說說非靜態的成員函數。 非靜態成員函數指針的類型&#xff1a; 類的非靜態成員是和類的對象相關的。也就是說&#xff0c;要通過類的對象來訪問變量。 成員函數的類型定義為&#xff1a; typedef void (A::*pfunc)(); A是一個類,有一個成員函數…

Windows下C語言連接Oracle數據庫

為什么80%的碼農都做不了架構師&#xff1f;>>> 最近公司有個項目需要用到Oracle數據庫&#xff0c;我負責前期的調研。由于項目要用到C和PHP兩種語言&#xff0c;所以先收集這兩種語言連接Oracle的方法。PHP使用的是Laravel框架&#xff0c;直接使用了Laravel-OCI…

SU suspecfk命令學習

用suplane生成平面&#xff0c;并查看其FK譜&#xff0c; 水平反射界面經FK變換后&#xff0c;波數為0&#xff0c; 正好處于臨界&#xff0c;乃奎斯特頻率&#xff0c; 有空間假頻&#xff0c; Over&#xff0c;不足之處&#xff0c;歡迎批評指正。 轉載于:https://www.cnblog…

dblink查詢_分庫數據如何查詢統計

分庫后的計算不能直接使用SQL&#xff1b;異構庫 SQL 函數不盡相同&#xff1b;JAVA 硬編碼實施難度大&#xff1b;即使借助透明網關訪問遠程數據庫&#xff0c;分庫性能優化也是頭疼問題。一般常規辦法&#xff1a;方法1&#xff1a;java硬編碼簡單的跨庫count運算&#xff0c…

python 爬取大樂透開獎結果

#codingutf-8 #下面中文注釋不支持 所以開頭加 "#codingutf-8" # 獲取近期大樂透開獎結果, 并給出自己猜中的個數import requests# 這個API能夠免費得到近期開獎結果, url里的-20代表獲取近20期的開獎信息 url "http://f.apiplus.net/dlt-20.json" re…

【Python五篇慢慢彈(5)】類的繼承案例解析,python相關知識延伸

類的繼承案例解析&#xff0c;python相關知識延伸 作者&#xff1a;白寧超 2016年10月10日22:36:57 摘要&#xff1a;繼<快速上手學python>一文之后&#xff0c;筆者又將python官方文檔認真學習下。官方給出的pythondoc入門資料包含了基本要點。本文是對文檔常用核心要點…

課堂練習之小強大掃蕩

標題&#xff1a;在將程序安裝到新的手機上時會出現程序崩潰 解決&#xff1a;1、找出錯誤&#xff1a;經過一系列測試&#xff0c;發現問題出現在第一次訪問數據庫的代碼時報錯。錯誤原因為不能發現數據庫中的建立的表。 2、如何解決&#xff1a;在主頁面加入訪問數據庫語句。…

領域驅動設計:軟件核心復雜性應對之道_人人都可以領域驅動設計(一)

最近幾年&#xff0c;領域驅動設計&#xff08;Domain-Driven Design&#xff0c;DDD&#xff09;這個術語越來越多地出現在軟件工程師的視野里。對DDD不熟悉的人可能會覺得它是軟件領域里的一個新的概念&#xff0c;但是實際上&#xff0c;Eric Evans在十幾年前就已經提出了這…

linux 進程通信 消息隊列

詳解linux進程間通信-消息隊列 前言&#xff1a;前面討論了信號、管道的進程間通信方式&#xff0c;接下來將討論消息隊列。 一、系統V IPC 三種系統V IPC&#xff1a;消息隊列、信號量以及共享內存&#xff08;共享存儲器&#xff09;之間有很多相似之處。 每個內核中的 I P …

laravel框架——composer導入laravel

第一種&#xff1a;  composer create-project --prefer-dist laravel/laravel projectName "5.2.*"第二種&#xff1a;  composer global require "laravel/installer"  laravel new 名稱轉載于:https://www.cnblogs.com/xj76149095/p/5951822.html…

第七章 心得體會

通過第七章的學習&#xff0c;使自己對驅動程序的認識更加深刻&#xff0c;LED燈的驅動程序幫我我學到很多&#xff0c;還學會了驅動的移植。 學到的知識&#xff1a; 一、編寫LED驅動 1、創建LED驅動的設備文件 第一步&#xff1a;使用cdev_init函數初始化cdev leds_cdev.owne…

wx.checkjsapi是寫在config里面嗎_用Python寫一個程序,解密游戲內抽獎的秘密

前言本文的文字及圖片來源于網絡,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯系我們以作處理。作者&#xff1a; 極客挖掘機PS&#xff1a;如有需要Python學習資料的小伙伴可以加點擊下方鏈接自行獲取http://t.cn/A6Zvjdun分析需求我們先整理下思…

Dev C++安裝第三方庫boost

Dev_C安裝第三方庫boost 安裝步驟 準備工作下載boost庫&#xff0c;下載地址https://sourceforge.net/projects/boost/1. 設置GCC的環境變量PATH 設置環境變量path,在其中加上DEV-C編譯器的路徑&#xff08;gcc.exe所在路徑&#xff09;&#xff0c;如C:\Program Files (x86)…

bash的一些小技巧

1、從輸入讀入變量 eg:read -ep "input yes or no: " flag 用e選項表示編輯&#xff0c;可以使用backspace刪除 2、數組 a、索引數組 declare -a arr(var1 var2 var3) 用空格分割&#xff0c;如果直接訪問變量$arr&#xff0c; 則獲取的是數組的第一個元素&#xff0…

golang switch_為什么程序員都不喜歡使用 switch ,而是大量的 if……else if ?

點擊上方“我要學編程”&#xff0c;選擇“置頂/星標公眾號”福利干貨&#xff0c;第一時間送達&#xff01;來自 | C語言Plus請用5秒鐘的時間查看下面的代碼是否存在bug。OK&#xff0c;熟練的程序猿應該已經發現Bug所在了&#xff0c;在第13行下面我沒有添加關鍵字break; 這就…

RabbitMQ 安裝與簡單使用

在企業應用系統領域&#xff0c;會面對不同系統之間的通信、集成與整合&#xff0c;尤其當面臨異構系統時&#xff0c;這種分布式的調用與通信變得越發重要。其次&#xff0c;系統中一般會有很多對實時性要求不高的但是執行起來比較較耗時的地方&#xff0c;比如發送短信&#…

數據庫函數依賴及范式

一、基礎概念   要理解范式&#xff0c;首先必須對知道什么是關系數據庫&#xff0c;如果你不知道&#xff0c;我可以簡單的不能再簡單的說一下&#xff1a;關系數據庫就是用二維表來保存數據。表和表之間可以……&#xff08;省略10W字&#xff09;。   然后你應該理解以下…

windows svn

windows svn 1.1Svn和VisualSvn介紹 VisualSvn Server2.5.6&#xff08;版本控制服務器&#xff09;免費開源軟件 是基于Windows平臺上的Subversion服務器&#xff0c;它是免費的 官方下載&#xff1a; http://www.visualsvn.com/files/VisualSVN-Server-2.5.6.msi TortoiseSvn…