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.mzph.cn/news/457827.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server -- SQLserver 存储过程执行错误记录到表

SQLserver 存储过程执行错误记录到表 From: http://blog.csdn.net/leshami/article/details/51333650 对于在执行存储过程中碰到的一些错误&#xff0c;如果未及时捕获或者说传递给前端应用程序来&#xff0c;在这样的情形下&#xff0c;故障的排查显得尤为困难。基于此&…

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五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸

类的继承案例解析&#xff0c;python相关知识延伸 作者&#xff1a;白宁超 2016年10月10日22:36:57 摘要&#xff1a;继<快速上手学python>一文之后&#xff0c;笔者又将python官方文档认真学习下。官方给出的pythondoc入门资料包含了基本要点。本文是对文档常用核心要点…

领域驱动设计:软件核心复杂性应对之道_人人都可以领域驱动设计(一)

最近几年&#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 …

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;比如发送短信&#…

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…

docker-compose下载慢_编写Docker Compose时要注意的五大常见错误

在构建容器化的应用时&#xff0c;开发人员往往需要某种方法来引导启动目标容器&#xff0c;以对其进行代码级别的测试。尽管业界有许多方法可以实现该目的&#xff0c;但Docker Compose是目前最受欢迎的一种方法。它能够让如下两个方面变得容易实现&#xff1a;指定在开发过程…

frame越过另一个frame_拥抱swoole(三)之用php实现一个混合服务器

混合服务器&#xff0c;就是可以同时支持http&#xff0c;websocket&#xff0c;tcp等的服务器&#xff0c;用swoole就是这么简单&#xff0c;分分钟&#xff0c;就可以愉快地搞物联网开发了&#xff0c;啥都支持&#xff0c;我采用官方的例子&#xff0c;创建一个混合服务器&a…

Hibernate学习系列————注解一对多单向实例

2019独角兽企业重金招聘Python工程师标准>>> 开发环境&#xff1a;MysqlEclipse 一对多单向的列子原理&#xff1a;一个班级&#xff0c;多个学生&#xff0c;学生端为多的一端&#xff0c;他们拥有一个外键指向相同的班级。 项目结构 需要的jar包 hibernate.cfg.xm…

sudo apt-get nmap 报错锁占用

在Ubuntu中用apt-get命令安装软件是出现如下错误&#xff1a; 网上搜了一下原因&#xff0c;说是有另外一个程序在运行&#xff0c;导致锁不可用&#xff0c;原因可能是赏析运行更新或安装没有正常完成。这是因为上次更新或者安装没有正常完成。 网上的两种解决方法&#xff1…

python逐行读取txt写入excel_用python从符合一定格式的txt文档中逐行读取数据并按一定规则写入excel(openpyxl支持Excel 2007 .xlsx格式)...

前几天接到一个任务&#xff0c;从gerrit上通过ssh命令获取一些commit相关的数据到文本文档中&#xff0c;随后将这些数据存入Excel中。数据格式如下图所示观察上图可知&#xff0c;存在文本文档中的数据符合一定的格式&#xff0c;通过python读取、正则表达式处理并写入Excel文…

Extjs 之 initComponent 和 constructor的区别(转)

在创建自定义类时&#xff0c;先构造&#xff08;constructor)后初始化&#xff08;initComponent&#xff09;。如&#xff1a;&#xff08;在旧的Extjs 版本中使用 Ext.extend 实现扩展&#xff09; Ext.define(Btn,{ extend:Ext.button.Button, init…

hive遍历_从Hive中的stored as file_foramt看hive调优

一、行式数据库和列式数据库的对比1、存储比较行式数据库存储在hdfs上式按行进行存储的&#xff0c;一个block存储一或多行数据。而列式数据库在hdfs上则是按照列进行存储&#xff0c;一个block可能有一列或多列数据。2、压缩比较对于行式数据库&#xff0c;必然按行压缩&#…