HTTP1.0 HTTP 1.1 HTTP 2.0主要区别

##HTTP1.0 HTTP 1.1主要区别

###长连接

HTTP 1.0需要使用keep-alive参数来告知服务器端要建立一个长连接,而HTTP1.1默认支持长连接。

HTTP是基于TCP/IP协议的,创建一个TCP连接是需要经过三次握手的,有一定的开销,如果每次通讯都要重新建立连接的话,对性能有影响。因此最好能维持一个长连接,可以用个长连接来发多个请求。

###节约带宽

HTTP 1.1支持只发送header信息(不带任何body信息),如果服务器认为客户端有权限请求服务器,则返回100,否则返回401。客户端如果接受到100,才开始把请求body发送到服务器。

这样当服务器返回401的时候,客户端就可以不用发送请求body了,节约了带宽。

另外HTTP还支持传送内容的一部分。这样当客户端已经有一部分的资源后,只需要跟服务器请求另外的部分资源即可。这是支持文件断点续传的基础。

###HOST域

现在可以web server例如tomat,设置虚拟站点是非常常见的,也即是说,web server上的多个虚拟站点可以共享同一个ip和端口。

HTTP1.0是没有host域的,HTTP1.1才支持这个参数。

##HTTP1.1 HTTP 2.0主要区别
###多路复用

HTTP2.0使用了多路复用的技术,做到同一个连接并发处理多个请求,而且并发请求的数量比HTTP1.1大了好几个数量级。

当然HTTP1.1也可以多建立几个TCP连接,来支持处理更多并发的请求,但是创建TCP连接本身也是有开销的。

TCP连接有一个预热和保护的过程,先检查数据是否传送成功,一旦成功过,则慢慢加大传输速度。因此对应瞬时并发的连接,服务器的响应就会变慢。所以最好能使用一个建立好的连接,并且这个连接可以支持瞬时并发的请求。

关于多路复用,可以参看学习NIO 。

###数据压缩

HTTP1.1不支持header数据的压缩,HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。

##服务器推送

意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。

服务器端推送的这些资源其实存在客户端的某处地方,客户端直接从本地加载这些资源就可以了,不用走网络,速度自然是快很多的。

参考的文章
1、
HTTP/2.0 相比1.0有哪些重大改进?
2、深入研究:HTTP2 的真正性能到底如何

04/12/2018 08:54 上午 posted in  HTTP

iOS中的内存管理

既然是内存管理,首先要知道那么内存是用来干什么的?内存具体管理的东西是什么?当然这些东西基本都是常识了,内存当然是用来存储数据的,内存要管理的东西简单的说也就是如何将数据存储到内存中(比如说我们的声明变量就可以将数据存储到内存中),其次存储到内存中的数据怎样释放,什么时候释放,这都是内存管理需要来关心的.

正文:

1.内存中的五大区域

内存分为5个区域,分别指的是----->栈区/堆区/BSS段/数据段/代码段

栈:存储局部变量,当其作用域执行完毕之后,就会被系统立即收回

堆:存储OC对象,手动申请的字节空间,需要调用free来释放

BSS段:未初始化的全局变量和静态变量,一旦初始化就会从BSS段中回收掉,转存到数据段中

数据段:存储已经初始化的全局变量和静态变量,以及常量数据,直到结束程序时才会被立即收回

代码段:代码,直到结束程序时才会被立即收回

2.OC中堆区存储对象的特点

除了堆区,其他区域的中存储的数据,都是又系统自动释放的

堆区中的OC对象,是不会自动释放的,如果不主动释放,那么将在程序结束的时候才去释放

3.引用计数器

首先简单来说一下,每一个OC对象都有一个属性,叫做retainCount,翻译过来也就是引用计数器,类型为unsigned long,占据8个字节,每一个对象负责维护对象所引用的记数值,当一个新的引用指向对象,那么这个对象的引用值增加1,当我们新创建出一个对象的时候这个对象的引用计数器的值默认为1,当这个对象被少一次引用的时候那么就先让这个对象的引用记数值减1,当这个对象所引用的记数值为0的时候,代表这个对象没有被使用,这时系统会自动回收掉此对象,回收这个对象的同时自动调用这个对象的dealloc方法

控制规则:

为对象发送一条retain消息,那么对象的引用计数器的值就会+1

为对象发送一条release消息,那么对象的引用计数器的值就会-1

为对象发送一条retainCount消息,那么就可以得到这个对象的引用计数器的值

4.内存管理的分类

MRC:Manual Reference Counting 手动引用计数器,需要我们手动管理对象引用计数器的值

ARC:Autimatic Reference Counting 自动引用计数器,系统自动的改变对象引用计数器的值(iOS5之后),ARC是基于MRC的

5.内存管理基本原则

新创建一个对象,这个对象的引用计数器的值为1,有对象的创建,就需要匹配一个release

是谁来负责retain的,谁就要负责release,使用的时候retain,不是用的时候release

retain的次数要和release次数想匹配,有加有减,做到平衡

6.野指针

在C中,声明一个指针变量,没有为这个指针变量初始化,那么这个指针变量的值也就是一个垃圾值,指针指向随机的一块空间,那么我们叫做野指针

在OC中,一个指针指向的对象被释放了,那么这个指针叫野指针

7.对象的回收

对象所占用的字节空间,分配给别人使用,系统未分配这块空间被别人使用之前,这个对象的数据仍然处在内存中

8.僵尸对象

已经被收回但是这个对象的数据仍然处在内存中,像这样的对象叫做僵尸对象

僵尸对象有可能可以访问也有可能不可以访问,当僵尸对象所占的内存空间还没有分配给别人使用的时候,这个数据的对象其实仍然存在,通过指针仍然可以找到这个对象,所以说这个时候僵尸对象还可以被访问,当这个僵尸对象已经分配给别人使用的时候,这个对象就不存在了,这个时候不可以被访问

注意:一旦一个对象成为僵尸对象之后,这个对象无论如何都不应该被使用,无论有没有分配给别人使用,都不能用!且不可以复活!

9.避免内存泄漏

有对象的创建,就必须要匹配一个release,retain和release的次数要匹配,不要随便为一个指针赋值为nil,除非这个指针是野指针,在方法中不要随意对传入的对象进行retain

当我们通过野指针去访问僵尸对象的时候会报错,为了避免报错当一个指针成为野指针后,为这个指针赋值为nil

FROM:https://blog.csdn.net/oboe_b/article/details/78140027

04/12/2018 08:47 上午 posted in  apple

iOS中防止中间人攻击

NSURLSession / NSURLConnection 防止中间人攻击,废话不多说直接上代码。
1、客户端发起网络请求

- (void)sendPostRequest:(NSString *)baseURL body:(NSString *)body BackGround:(BOOL)isBack completion:(void (^)(NSDictionary *dict))completion onError:(void (^)(NSError *error))onError
{
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
     
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration
                                                          delegate:self
                                                     delegateQueue:self.sessionQueue];
     
    NSString *requestString = [NSString stringWithFormat:@"%@",baseURL];
     NSData *bodyData = [body dataUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:requestString];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
     
    [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
    [request setHTTPShouldHandleCookies:NO];
     
    [request setHTTPMethod:@"POST"];
    [request setTimeoutInterval:10];
    [request setHTTPBody:bodyData];
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
     
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
                                                 
                                                [Util complete_handler:response
                                                               baseurl:baseURL
                                                                  data:data
                                                                 error:error
                                                            completion:completion
                                                               onError:onError];
                                            }];
    [task resume];
 
}

在这里不需要解释太多NSURLSession / NSURLConnection 大同小异,如果这都有难度,下面的请忽略。

2、在接手做这个东西的时候由于国内关于这方面的资料几乎没有,然后只能自己查阅相关文档。
AFNetworking 会比系统提供的简单许多,在这里就不解释了。这里主要是对NSURLSession 进行描述。
我们主要对其代理方法:

- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 
 
                                             completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler;

下面就是详细步骤;

	#pragma mark - NSURLSessionDelegate 
//用过CF的东西,你一定要记得释放呀,不然你就太水了 

复制代码
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * __nullable credential))completionHandler
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        do {
//读取本地证书
            NSString *path = [[NSBundle mainBundle] pathForResource:@"Geo_Trust_Der" ofType:@"der"];
            NSData *certificateData = [NSData dataWithContentsOfFile:path];
            SecCertificateRef localCertificate =  SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certificateData);
//这个方法后面会有代码
            SecKeyRef localKey = [self getPublicKeyWithCertificateData:localCertificate]; 
            SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
             
            NSMutableArray *serverCertificates = [NSMutableArray array];
            CFIndex certCount = SecTrustGetCertificateCount(serverTrust);
//证书链  什么?这你都不知道? 好吧 ,百度一下就知道了
            for (CFIndex certIndex = 0; certIndex < certCount; certIndex++) {
                SecCertificateRef   thisCertificate;                
                thisCertificate = SecTrustGetCertificateAtIndex(serverTrust, certIndex);
                [serverCertificates addObject:(__bridge id)thisCertificate];
            }
            SecCertificateRef serverCertificate = (__bridge SecCertificateRef)([serverCertificates lastObject]);
/*读取公钥,在这里为什么这么说呢 ,证书有很多东西可以读取,包括指纹等等,不知道? 自行百度
*/
            SecKeyRef serverKey = [self getPublicKeyWithCertificateData:serverCertificate];
//这里我们判断两个公钥的二进制数据是否一致 
            if ([[self getPublicKeyBitsFromKey:localKey] isEqualToData:[self getPublicKeyBitsFromKey:serverKey]]) {
                NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust];
                [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
                completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
            } else {
                [challenge.sender cancelAuthenticationChallenge:challenge];
            }
            CFRelease(serverKey);
             
            CFRelease(localKey);
            CFRelease(localCertificate);
        } while (0);
    }   
}

至此你已经顺利完成了。那我现在附上上面的两个功能函数
//获取证书

- (SecKeyRef)getPublicKeyWithCertificateData:(SecCertificateRef)myCertificate
{
    SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
    SecTrustRef myTrust;
    OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
    SecTrustResultType trustResult;
    if (status == noErr) {
        SecTrustEvaluate(myTrust, &trustResult);
    }
    SecKeyRef localPBKey = SecTrustCopyPublicKey(myTrust);
    CFRelease(myPolicy);
    CFRelease(myTrust);
     
    return localPBKey;
}

//读取公钥数据

- (NSData *)getPublicKeyBitsFromKey:(SecKeyRef)givenKey {
     
    static const uint8_t publicKeyIdentifier[] = "随便写!";
    NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
     
    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;
     
    NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
     
    // Temporarily add key to the Keychain, return as data:
    NSMutableDictionary * attributes = [queryPublicKey mutableCopy];
    [attributes setObject:(__bridge id)givenKey forKey:(__bridge id)kSecValueRef];
    [attributes setObject:@YES forKey:(__bridge id)kSecReturnData];
    CFTypeRef result;
    sanityCheck = SecItemAdd((__bridge CFDictionaryRef) attributes, &result);
    if (sanityCheck == errSecSuccess) {
        publicKeyBits = CFBridgingRelease(result);
         
        // Remove from Keychain again:
        (void)SecItemDelete((__bridge CFDictionaryRef) queryPublicKey);
    }
     
    return publicKeyBits;
}
04/10/2018 09:27 上午 posted in  HTTP

KVO的实现机理,随便解释一下isa-swizzling

isa-swizzling
isa, is a kind of
swizzling, 混合,搅合。
KVO的基础KVC。
KVC主要通过isa-swizzling,来实现。

[site setValue:@"sitename" forKey:@"name"];

编译器处理成:

SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (site->isa,sel);
method(site, sel, @"sitename", @"name");

Selectors

Selectors are the run-time system's identifier for a method. The SEL data type is used for selectors.

The sel_get_uid() function can be used to get a method's selector from it's name:

objc_msg_lookup

If we want to get an IMP using the Objective-C runtime functions, then use objc_msg_lookup(id,SEL) on the GNU runtime.

What is an IMP? How do I get one?

IMP is a C type referring to the implementation of a method, also known as an implementation pointer. It's a pointer to a function returning id, and with self and a method selector (available inside method definitions as the variable _cmd) as the first arguments:

id (*IMP)(id, SEL, ...);
With NSObject, you can obtain the IMP for a given method by doing:

IMP imp=[obj methodForSelector:@selector(message)];
For Object, do:

IMP imp=[obj methodFor:@selector(message)];
How do I send a message given an IMP?
Dereference it, as with a C function pointer:

id anObject, theResult;
IMP someImp;
SEL aSelector;
...
theResult=someImp(anObject,aSelector);

=================

When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.

Instead of relying on the isa pointer your application should use the class method to determine the class of an object instance.

键-值观察实现细节
自动键-值观察是由叫isa-swizzling的技术实现的。

isa指针,如其名称所指,指向维护分发表的对象的类。该分发表实际上包含了指向实现类中的方法的指针,和其它数据。

当某个对象的属性注册了中观察者时,当该被观察对象的isa指针被修改为指向一个中间类,而不是真实的类。因此isa指针的值并不一定反映实例的实际类。

你的程序应当使用class方法来确定实例对象的类,而不是依赖于isa指针。

04/02/2018 08:25 上午 posted in  Runtime

iOS开发线程和RunLoop

03/28/2018 10:10 上午 posted in  内核编程

OC-消息转发机制

当正常的消息发送走不通的时候,会走下面的消息转发机制:

消息转发机制基本分为三个步骤:

1、动态方法解析

2、备用接受者

3、完整转发

新建一个HelloClass的类,定义两个方法:

@interface HelloClass : NSObject
- (void)hello;
+ (HelloClass *)hi;
@end

##动态方法解析

对象在接收到未知的消息时,首先会调用所属类的类方法+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方法)。在这个方法中,我们有机会为该未知消息新增一个”处理方法”“。不过使用该方法的前提是我们已经实现了该”处理方法”,只需要在运行时通过class_addMethod函数动态添加到类里面就可以了。

void functionForMethod(id self, SEL _cmd)
{
    NSLog(@"Hello!");
}

Class functionForClassMethod(id self, SEL _cmd)
{
    NSLog(@"Hi!");
    return [HelloClass class];
}

#pragma mark - 1、动态方法解析
+ (BOOL)resolveClassMethod:(SEL)sel
{
    NSLog(@"resolveClassMethod");
    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@"hi"])
    {
         Class metaClass = objc_getMetaClass("HelloClass");
         class_addMethod(metaClass, @selector(hi), (IMP)functionForClassMethod, "v@:");
         return YES;
    }
    return [super resolveClassMethod:sel];
}

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"resolveInstanceMethod");

    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@"hello"])
    {
         class_addMethod(self, @selector(hello), (IMP)functionForMethod, "v@:");
         return YES;
    }
    return [super resolveInstanceMethod:sel];
}

##备用接受者

动态方法解析无法处理消息,则会走备用接受者。这个备用接受者只能是一个新的对象,不能是self本身,否则就会出现无限循环。如果我们没有指定相应的对象来处理aSelector,则应该调用父类的实现来返回结果。

#pragma mark - 2、备用接收者
- (id)forwardingTargetForSelector:(SEL)aSelector
{
    NSLog(@"forwardingTargetForSelector");

    NSString *selectorString = NSStringFromSelector(aSelector);

    // 将消息交给_helper来处理
    if ([selectorString isEqualToString:@"hello"]) {
        return _helper;
    }
    return [super forwardingTargetForSelector:aSelector];
}

在本类中需要实现这个新的接受对象

@interface HelloClass ()
{
    RuntimeMethodHelper *_helper;
}
@end

@implementation HelloClass
- (instancetype)init
{
    self = [super init];
    if (self) 
    {
         _helper = [RuntimeMethodHelper new];
    }
    return self;
}

RuntimeMethodHelper 类需要实现这个需要转发的方法:

#import "RuntimeMethodHelper.h"

@implementation RuntimeMethodHelper
- (void)hello
{
    NSLog(@"%@, %p", self, _cmd);
}
@end

##完整消息转发

如果动态方法解析和备用接受者都没有处理这个消息,那么就会走完整消息转发:

#pragma mark - 3、完整消息转发
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSLog(@"forwardInvocation");
    if ([RuntimeMethodHelper instancesRespondToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:_helper];
    }
}

/*必须重新这个方法,消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象*/
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature)
    {
        if ([RuntimeMethodHelper instancesRespondToSelector:aSelector])
        {
            signature = [RuntimeMethodHelper instanceMethodSignatureForSelector:aSelector];
        }
    }
    return signature;
}
03/28/2018 09:59 上午 posted in  Runtime

Https单向认证和双向认证

一、Http

HyperText Transfer Protocol,超文本传输协议,是互联网上使用最广泛的一种协议,所有WWW文件必须遵循的标准。HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全。

使用TCP端口为:80

二、Https

Hyper Text Transfer Protocol over Secure Socket Layer,安全的超文本传输协议,网景公式设计了SSL(Secure Sockets Layer)协议用于对Http协议传输的数据进行加密,保证会话过程中的安全性。

使用TCP端口默认为443

三、SSL协议加密方式

SSL协议即用到了对称加密也用到了非对称加密(公钥加密),在建立传输链路时,SSL首先对对称加密的密钥使用公钥进行非对称加密,链路建立好之后,SSL对传输内容使用对称加密。

对称加密
速度高,可加密内容较大,用来加密会话过程中的消息

公钥加密
加密速度较慢,但能提供更好的身份认证技术,用来加密对称加密的密钥

四、单向认证

Https在建立Socket连接之前,需要进行握手,具体过程如下:

客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
客户端使用服务端返回的信息验证服务器的合法性,包括:

证书是否过期
发型服务器证书的CA是否可靠
返回的公钥是否能正确解开返回证书中的数字签名
服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信,否则,终止通信

客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
服务器端在客户端提供的加密方案中选择加密程度最高的加密方式。
服务器将选择好的加密方案通过明文方式返回给客户端
客户端接收到服务端返回的加密方式后,使用该加密方式生成产生随机码,用作通信过程中对称加密的密钥,使用服务端返回的公钥进行加密,将加密后的随机码发送至服务器
服务器收到客户端返回的加密信息后,使用自己的私钥进行解密,获取对称加密密钥。
在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。
五、双向认证

双向认证和单向认证原理基本差不多,只是除了客户端需要认证服务端以外,增加了服务端对客户端的认证,具体过程如下:

客户端向服务端发送SSL协议版本号、加密算法种类、随机数等信息。
服务端给客户端返回SSL协议版本号、加密算法种类、随机数等信息,同时也返回服务器端的证书,即公钥证书
客户端使用服务端返回的信息验证服务器的合法性,包括:

证书是否过期
发型服务器证书的CA是否可靠
返回的公钥是否能正确解开返回证书中的数字签名
服务器证书上的域名是否和服务器的实际域名相匹配
验证通过后,将继续进行通信,否则,终止通信

服务端要求客户端发送客户端的证书,客户端会将自己的证书发送至服务端
验证客户端的证书,通过验证后,会获得客户端的公钥
客户端向服务端发送自己所能支持的对称加密方案,供服务器端进行选择
服务器端在客户端提供的加密方案中选择加密程度最高的加密方式
将加密方案通过使用之前获取到的公钥进行加密,返回给客户端
客户端收到服务端返回的加密方案密文后,使用自己的私钥进行解密,获取具体加密方式,而后,产生该加密方式的随机码,用作加密过程中的密钥,使用之前从服务端证书中获取到的公钥进行加密后,发送给服务端
服务端收到客户端发送的消息后,使用自己的私钥进行解密,获取对称加密的密钥,在接下来的会话中,服务器和客户端将会使用该密码进行对称加密,保证通信过程中信息的安全。

https通讯步骤:

1)客户端请求服务器,发送握手消息

2)服务器返回客户端自己的加密算法、数字证书和公钥;

3)客户端验证服务器端发送来的数字证书是否与本地受信任的证书相关信息一致;如果不一致则客户端浏览器提示证书不安全
如果验证通过,则浏览器会采用自身的随机数算法产生一个随机数,并用服务器发送来的公钥加密;发送给服务器;这里如果有人通过攻击获取了这个消息,那也没用,因为他没有解密此段消息所需要私钥;验证通过的网站在浏览器地址栏的右边会有一安全锁的标识;

4)服务器解密得到此随机数,并用此随机数作为密钥采用对称加密算法加密一段握手消息发送给浏览器;

5)浏览器收到消息后解密成功,则握手结束,后续的信息都通过此随机密钥加密传输。

以上是服务端认证的情况,如果服务端对访问的客户端也有认证需求,则客户端也需要将自己的证书发送给服务器,服务器认证不通过,通讯结束;原理同上;

另外,一般在传输过程中为了防止消息窜改,还会采用消息摘要后再加密的方式,以此保证消息传递的正确性。

数字证书的内容

X.509 应该是比较流行的 SSL 数字证书标准,包含(但不限于)以下的字段:

字段 值说明
对象名称(Subject Name) 用于识别该数字证书的信息
共有名称(Common Name) 对于客户证书,通常是相应的域名
证书颁发者(Issuer Name) 发布并签署该证书的实体的信息
签名算法(Signature Algorithm) 签名所使用的算法
序列号(Serial Number) 数字证书机构(Certificate Authority, CA)给证书的唯一整数,一个数字证书一个序列号
生效期(Not Valid Before) (`・ω・´)
失效期(Not Valid After) (╯°口°)╯(┴—┴
公钥(Public Key) 可公开的密钥
签名(Signature) 通过签名算法计算证书内容后得到的数据,用于验证证书是否被篡改
除了上述所列的字段,还有很多拓展字段,在此不一一详述。

下图为 Wikipedia 的公钥证书:

03/24/2018 08:21 上午 posted in  HTTP

区块链的概念和应用

从狭义上来讲,区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一 种链式数据结构,并以密码学方式保证的不可篡改和不可伪造的分布式账本;而从广义上来讲,区块链技术是利用块链式数据结构来验证与存储数据、利用分布式节点共识算法来生成和更新数据、利用密码学的方式保证数据传输和访问的安全、利用由自动化脚本代码组成的智能合约来编程和操作数据的一种全新的分布式基础架构与计算范式。

由于区块链技术具有去中心化、开放性、自治性、匿名性、信息不可篡改等天然特性,因此被认为是继蒸汽机、电力、互联网之后,下一代颠覆性的核心技术。而这种颠覆,并不是我们通常所说的提升效率,而是对生产关系的一种重构,进而改变整个世界。

从这个意义上说,区块链受到了极大的追捧,从而在近年来大火特火。

一般来说,业内比较认可的、可以用区块链的一些领域大概有智能合约证券交易电子商务物联网社交通讯文件存储存在性证明身份验证股权众筹等。不过从技术发展阶段上来看,目前在金融领域,区块链的应用是相对最为成熟的。

自从诞生以来,区块链已经经过了三次演化,分别是:区块链1.0、区块链2.0和区块链3.0,而每一个阶段都有其对应的应用。

具体来说,区块链1.0就是比特币。不过除此之外最著名的当属瑞波币(Ripple)、莱特币等,其最重要的功能是支付。由于瑞波币拥有极为便利的国际转账支付功能,因此包括国内多家银行在内的全球很多银行目前都在使用瑞波币系统。同时,银行与瑞波币的合作也被看做是银行在拥抱区块链技术、寻求自身发展变革的标志。

随后,区块链技术进入了2.0时代,以太坊(ETH)和EOS等为其典型代表。区块链2.0有了一个重要功能:智能合约,它突破性的解决了区块链的互信难题,使得交易更加安全。其中公信宝(GXS)被看做是比较成功的一个应用,在银行、保险、证券领域有着不小的市场。

目前,已经发展到了区块链3.0时代,DAO(区块链自治组织)、DAC(区块链自治公司)等相继出现。他们坚信区块链将在未来彻底改变世界,不过,除了在物联网(IOTA,网易近期也在积极布局)等少数领域之外,尚未发现有价值的应用点。

区块链生态系统逐渐完善,部分地方政府开始试水

可以说,国内的区块链技术与应用并不落后于国外,甚至有某些方面还有所超越。但尽管如此,国内的区块链生态系统目前还只是处于起步的初级阶段,不过在各行各业已经引起了广泛关注,并且开始有越来越多不同细分领域的积极探索和试验。

苏州同济金融科技研究院副院长祝文伟说:“区块链技术作为一项底层技术,基于其基本特点,最初主要解决的是交易的信任和安全问题,区块链上的所有交易都会在全网进行备案;而由于其‘分布式及去中心化’的明显特征,区块链技术初期在供应链溯源、身份验证、防伪存证、电子档案等行业有相对较明显的应用优势和前景。”

区块链系统最初以矿场、矿机、矿池结合云算力体系形成了行业基础设施体系,随着以数字货币、电子钱包和交易所构成的数字资产体系的不断发展,以及区块链行业应用解决方案的不断落地。可以说,目前国内的区块链生态系统闭环正在形成。

对于区块链的未来发展前景,INB基金投资经理李万才认为,区块链将会实现真正的意义上的、全面彻底的业态颠覆,“与AI对行业的促进和提升效率不同,区块链对行业的颠覆完全是不同量级的。”

正是因为区块链的前景巨大,因此,随着区块链进入“寒武纪大爆发”,各地政府也开始纷纷布局这一新兴技术和产业。

就在上个月23日的“链谷成果、政策、场景规划”发布会上,苏州高铁新城管委会正式发布《区块链产业发展扶持政策》,业内也称“苏九条”,细分为落户扶持、经营扶持、人才扶持、平台扶持等9条内容。

比如,在落户扶持中,当地政府将成立专项服务小组,对入驻的区块链企业提供场景落地的对接服务,据悉2018年将开放30个场景;对新设立经认定的区块链企业或机构,提供不超过1000平方米的场地,并实施租金“两免三减半”政策,每年每家企业租金补助金额最高不超过60万元。在经营扶持中,对区块链企业(机构)按年度收入的不同,分别给予10万元、20万元、100万元、200万元的一次性奖励。用最优的服务、开放的场景、真金白银向区块链行业从业者发出诚挚的邀请。

区块链虽然发展迅速,但目前还远远没有成熟
虽然近年来,关于区块链的公司很多,资本也在大肆追捧,但我们仍然不能说区块链已经很成熟了。正如李万才也在观点中表示,“区块链(暂时还尚未成熟),可能在几年内会有成熟的行业应用出来,并让它逐渐走进大众视野。”

长期关注和解读区块链的“白话区块链”公众号创始人馋嘴猫也持有同样观点,“区块链目前还没有有价值的行业应用,区块链技术也并未具有完全的不可替代性;同时,区块链技术本身发展阶段也在初期,比如它对银行账单的处理效率就相当低下。”

据馋嘴猫介绍,目前比特币的处理速度最多每秒7笔交易,作为区块链2.0的以太坊也只是15-20笔交易左右。这个效率还难以在现实世界中发挥作用。

此外,从技术的人才储备上看,国内的情况更是不容乐观。据业内知情人士透露,“目前我们具有区块链开发能力的人才太少,国内真正具备开发能力的技术人员只有100人左右,最多不会超过200人。”

布比区块链创始人兼CEO蒋海认为,目前区块链技术层面还存在很大的改进和提升空间。

他说:“关于改进和提升,主要体现在两大个方面:第一是性能,区块链的处理性能有待进一步突破。由于采用多中心机制,要保证一致性和共识,规模与效率的均衡,这是一个难题。

“其次是隐私保护和权限控制。在实际商业应用中,需要具备隐私保护和权限控制等功能,共享与保护的均衡,是另一个难题。”

而国内更有对区块链持更加悲观甚至抵制态度的也大有人在,如2017年年底金沙江创业投资基金董事总经理朱啸虎就曾直言不讳地说:“我始终认为99.99%通过区块链/ICO融资的项目都是骗子!”

结语:
苏州同济金融科技研究院副院长祝文伟说:“随着技术和行业的不断发展,行业解决方案将基于侧链、交叉链、间隔链等的技术应用演变,进一步影响金融交易的清算和结算、电子商务支付和转账、物联网、网络安全、公正防伪、社交网络、慈善公益、版权交易、交通能源等各个产业。也许,未来的区块链技术真的能对目前的互联网行业应用进行改革性的颠覆和转换,最终,时间将给出答案和验证。”

01/11/2018 16:51 下午 posted in  BlockChain

git命令行工作环境配置

##git config 简要介绍

git的配置选项有三种:–system,–global 和 –local

  1. system是系统级别的全局设置,对所有电脑用户生效,文件在/etc/gitconfig;
  2. global是个人用户的全局配置,对所有个人用户的代码库生效,文件在$HOME/.config/git/config或者~/.gitconfig;
  3. local是代码库的设置,仅对设置的代码库生效,文件在代码库的.git/config。

git config常用命令

# 显示全局配置信息
git config --global --list
# 设置全局的用户名和邮箱
git config --global user.name "wellphone"
git config --global user.email wellphone@example.com
# 开启颜色
git config --global color.ui true

更详细的配置见Git-详细配置

##设置别名
git 命令一般较长,如果想少输入几个字可以设置别名,如下:

git config --global alias.st status
git config --global alias.ci commit
git config --global alias.co checkout
git config --global alias.br branch

除此之外,还可以创造自己的命令。比方说取消暂存文件时的输入比较繁琐,可以自己设置一下:

git config --global alias.unstage 'reset HEAD --'

然后,取消暂存文件的时候,只需要输入:

git unstage file

##自定义log显示
默认不用任何参数的话,git log会按提交时间列出所有的更新,最近的更新排在最上面。每次更新都有一个SHA-1校验和、作者的名字和电子邮件地址、提交时间,最后缩进一个段落显示提交说明。但是没有图形化的分支图表来的直接美观。还好,git给我们提供了一个常用的 –pretty选项,可以指定使用完全不同于默认格式的方式展示提交历史。比如用 oneline将每个提交放在一行显示,这在提交数很大时非常有用。另外还有 short,full 和 fuller 可以用,展示的信息完全可以按照自己的喜好来。

比如笔者自己配置的这条命令:

git log --color --graph --pretty=format:'%C(yellow)%h%Creset%C(cyan)%C(bold)%C(red)%d%Creset %s %C(green)[%cn] %Creset%C(cyan)[%cd]%Creset' --date=format-local:'%m-%d %H:%M'

图:

当然,我们可以使用别名的方法来使用这条命令:

git config --global alias.lg "log --color --graph --pretty=format:'%C(yellow)%h%Creset%C(cyan)%C(bold)%C(red)%d%Creset %s %C(green)[%cn] %Creset%C(cyan)[%cd]%Creset' --date=format-local:'%m-%d %H:%M'"

输入上条命令后,以后只需要输入git lg就可以看到自定义显示的log。

更多关于log配置信息可以查看Git-基础-查看提交历史

##设置自动补全命令
git 命令没有自动补全功能,这个在命令行下让人非常抓狂,尤其是在各个分支间切换的时候,狂按tab键也不能补全分支的名字。还好,有git的资深开发为我等小白准备好了自动补全功能。

如果用的是Bash shell,到git的官方源码库中的git/contrib/compleion文件夹git compleiton下载git-completion.bash文件。 将该文件复制到你自己的用户主目录中(译注:按照下面的示例,还应改名加上点:cp git-completion.bash ~/.git-completion.bash),并把下面一行内容添加到你的 .bashrc 文件中:

source ~/.git-completion.bash

在输入 Git 命令的时候可以敲两次跳格键(Tab),就会看到列出所有匹配的可用命令建议。

如图:

##设置命令prompt提示
我们在使用sourceTree的时候可以很方便看见当前工作的分支,work区,stage区的修改情况。但是在命令行下,我们需要执行git status才能知道这些信息,显得不是很方便。这个情况也有资深开发替我们解决了。我们只需要简单配置下就能在命令行的prompt提示中看见当前分支及修改情况。

同样的我们需要在git官方代码库中下载git-prompt.sh文件。

  1. 将下载下来的文件复制到~目录下。(e.g. ~/.git-prompt.sh)
  2. 将以下命令加入到~/.bash_profile或者是~/.bashrc文件里
source ~/.git-prompt.sh
  1. 修改自己的环境变量中的PS1值,PROMPT_COMMAND值
export PS1='[u@h W$(__git_ps1 " (%s)")]$ '
export PROMPT_COMMAND='__git_ps1 "u@h:W" "\$ "'

这时,在命令行提示符上已经可以显示当前的分支名了。
设置如下环境变量值

export GIT_PS1_SHOWDIRTYSTATE=true
export GIT_PS1_SHOWCOLORHINTS=true
export GIT_PS1_SHOWUNTRACKEDFILES=true
export GIT_PS1_SHOWUPSTREAM="auto"

如果设置GIT_PS1_SHOWDIRTYSTATE为非空值,则会使用(*)表示有文件未放入暂存区(unstaged files),(+)表示暂存区有文件(staged files)。

如果设置GIT_PS1_SHOWUNTRACKEDFILES为非空值,则会使用(%)表示有没有加入到git中的文件(untracked files)。

如果设置GIT_PS1_SHOWCOLORHINTS为非空值,则会显示颜色。 如果设置GIT_PS1_SHOWUPSTREAM=“auto”,则会使用(<)表示当前节点落后远程分支,(>)表示远程分支节点落后当前分支,(=)表示当前分支和远程分支一样,(<>)表示当前分支同远程分支分叉了。 如图:

##总结

以上只是笔者在日常工作中碰见的一些简单git配置方法,如果大家有更好更高效率的git命令使用方法,欢迎留言分享~~~ 附:git使用手册

11/15/2017 11:24 上午 posted in  Git

[阿里云ECS]GitLab的安装及使用

##前言
GitLab是利用 Ruby on Rails 一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。

它拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。

团队成员可以利用内置的简单聊天程序(Wall)进行交流。
它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。

###Git的家族成员

Git:是一种版本控制系统,是一个命令,是一种工具。
Gitlib:是用于实现Git功能的开发库。
Github:是一个基于Git实现的在线代码托管仓库,包含一个网站界面,向互联网开放。
GitLab:是一个基于Git实现的在线代码仓库托管软件,你可以用gitlab自己搭建一个类似于Github一样的系统,一般用于在企业、学校等内部网络搭建git私服。

###Gitlab的服务构成

Nginx:静态web服务器。
gitlab-shell:用于处理Git命令和修改authorized keys列表。
gitlab-workhorse:轻量级的反向代理服务器。
logrotate:日志文件管理工具。
postgresql:数据库。
redis:缓存数据库。
sidekiq:用于在后台执行队列任务(异步执行)。
unicorn:An HTTP server for Rack applications,GitLab Rails应用是托管在这个服务器上面的。

###GitLab工作流程

###GitLab Shell
GitLab Shell有两个作用:为GitLab处理Git命令、修改authorized keys列表。

当通过SSH访问GitLab Server时,GitLab Shell会:
限制执行预定义好的Git命令(git push, git pull, git annex)
调用GitLab Rails API 检查权限
执行pre-receive钩子(在GitLab企业版中叫做Git钩子)
执行你请求的动作 处理GitLab的post-receive动作
处理自定义的post-receive动作

当通过http(s)访问GitLab Server时,工作流程取决于你是从Git仓库拉取(pull)代码还是向git仓库推送(push)代码。

如果你是从Git仓库拉取(pull)代码,GitLab Rails应用会全权负责处理用户鉴权和执行Git命令的工作;
如果你是向Git仓库推送(push)代码,GitLab Rails应用既不会进行用户鉴权也不会执行Git命令,它会把以下工作交由GitLab Shell进行处理:

  1. 调用GitLab Rails API 检查权限
  2. 执行pre-receive钩子(在GitLab企业版中叫做Git钩子)
  3. 执行你请求的动作
  4. 处理GitLab的post-receive动作
  5. 处理自定义的post-receive动作

###GitLab Workhorse
GitLab Workhorse是一个敏捷的反向代理。它会处理一些大的HTTP请求,比如文件上传、文件下载、Git push/pull和Git包下载。其它请求会反向代理到GitLab Rails应用,即反向代理给后端的unicorn

##Gitlab环境部署
ECS配置要求:内存2G以上

方法一:镜像部署

镜像名称:GitLab代码管理(Centos 64位 | GitLab) | 镜像帮助文档

进入镜像详情页面,单击立即购买,按提示步骤购买 ECS 实例。

购买完成之后,登录”ECS 管理控制台”,在左边导航栏里,单击”实例”,进入 ECS 实例列表页,选择所购 ECS 实例所在的地域,并找到所购 ECS 实例,在”IP 地址”列获取该实例的公网 IP 地址。

注意:镜像部署好后默认是禁止远端访问的,所以直接访问ECS服务器的公网IP是不能访问到GitLab的登录界面的,请先运行/alidata目录下的gitlab_opennet.sh脚本,开启远程访问,然后再通过浏览器访问公网IP来访问GitLab的主页。

方法二:手动部署:

1、配置yum源

vim /etc/yum.repos.d/gitlab-ce.repo

复制以下内容:

[gitlab-ce]
name=gitlab-ce
baseurl=http://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7
Repo_gpgcheck=0
Enabled=1
Gpgkey=https://packages.gitlab.com/gitlab/gitlab-ce/gpgkey
       https://packages.gitlab.com/gitlab/gitlab-ce/gpgkey/gitlab-gitlab-ce-3D645A26AB9FBD22.pub.gpg
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
metadata_expire=300

2、更新本地yum缓存

sudo yum makecache

3、安装GitLab社区版

sudo yum install gitlab-ce        #自动安装最新版
//sudo yum install gitlab-ce-x.x.x    #安装指定版本

GitLab常用命令:

sudo gitlab-ctl start    # 启动所有 gitlab 组件;
sudo gitlab-ctl stop        # 停止所有 gitlab 组件;
sudo gitlab-ctl restart        # 重启所有 gitlab 组件;
sudo gitlab-ctl status        # 查看服务状态;
sudo gitlab-ctl reconfigure        # 启动服务;
sudo vim /etc/gitlab/gitlab.rb        # 修改默认的配置文件;
gitlab-rake gitlab:check SANITIZE=true --trace    # 检查gitlab;
sudo gitlab-ctl tail        # 查看日志;

4、修改配置文件

#修改url,供外部访问
[root@gitlab ~]# vi /etc/gitlab/gitlab.rb
external_url'http://gitlab.server.com'
external_url 修改成自己的ip或者域名
#修改配置文件之后,需要重新是配置文件生效下,初始化下
[root@gitlab ~]#gitlab-ctl reconfigure #这里会花费一定的时间(1-10min),如果这里内存小,将会花费大量时间

Recipe: gitlab::gitlab-rails
  *execute[clear the gitlab-rails cache] action run
    -execute /opt/gitlab/bin/gitlab-rake cache:clear
  *execute[clear the gitlab-rails cache] action run
    -execute /opt/gitlab/bin/gitlab-rake cache:clear
Recipe: gitlab::unicorn
  *service[unicorn] action restart
    -restart service service[unicorn]
Recipe: gitlab::redis
  *ruby_block[reload redis svlogd configuration] action create
    -execute the ruby block reload redis svlogd configuration
Recipe: gitlab::postgresql
  *ruby_block[reload postgresql svlogd configuration] action create
    -execute the ruby block reload postgresql svlogd configuration
Recipe: gitlab::unicorn
  *ruby_block[reload unicorn svlogd configuration] action create
    -execute the ruby block reload unicorn svlogd configuration
Recipe: gitlab::sidekiq
  *ruby_block[reload sidekiq svlogd configuration] action create
    -execute the ruby block reload sidekiq svlogd configuration
Recipe: gitlab::gitlab-workhorse
  *service[gitlab-workhorse] action restart
    -restart service service[gitlab-workhorse]
  *ruby_block[reload gitlab-workhorse svlogd configuration] action create
    -execute the ruby block reload gitlab-workhorse svlogd configuration
Recipe: gitlab::gitlab-workhorse
  *service[gitlab-workhorse] action restart
    -restart service service[gitlab-workhorse]
  *ruby_block[reload gitlab-workhorse svlogd configuration] action create
    -execute the ruby block reload gitlab-workhorse svlogd configuration
Recipe: gitlab::nginx
  *ruby_block[reload nginx svlogd configuration] action create
    -execute the ruby block reload nginx svlogd configuration
Recipe: gitlab::logrotate
  *ruby_block[reload logrotate svlogd configuration] action create
    -execute the ruby block reload logrotate svlogd configuration
 
Running handlers:
Running handlers complete
Chef Client finished, 222/309 resources updatedin 02 minutes 50 seconds
`该过程还要进行域名解析或者IP指定`

5、启动Gitlab服务

[root@gitlab ~]# gitlab-ctl start
ok: down:gitaly: 0s, normally up
ok: down:gitlab-monitor: 1s, normally up
ok: down: gitlab-workhorse: 0s, normally up
ok: down: logrotate: 0s, normally up
ok: down: nginx: 0s, normally up
ok: down:node-exporter: 0s, normally up
ok: down:postgres-exporter: 1s, normally up
ok: down: postgresql: 0s, normally up
ok: down:prometheus: 1s, normally up
ok: down: redis: 0s, normally up
ok: down:redis-exporter: 0s, normally up
ok: down: sidekiq: 0s, normally up
ok: down: unicorn: 1s, normally up
注解:
绿色部分是9中新添加的
ü gitlab-workhorse这个“工作马”,就是gitlab-Git-http-server(GitlabV8.0出现,V8.2名称变更为Gitlab-workhorse)
ü sidekiq多线程启动
ü unicorn是ruby的http server,可以通过
http://localhost:8080端口访问, 默认端口是8080
ü nginx作为方向代理,代理到unicorn,nginx默认端口是80
ü postgresql作为数据库,默认端口是5432
ü redis作为一个队列(NoSql),用于存储用户session和任务,任务包括新建仓库、发送邮件等等,默认端口是6379
ü logrotate切割日志
ü prometheus监控,默认端口9090
ü gitlab-monitor默认端口9168
注:
(可选)如果系统资源不足,可以通过以下命令关闭Sidekiq来释放一部分内存
[root@gitlab ~]# gitlab-ctl stop sidekiq
ok: down: sidekiq: 0s, normally up

参考:
https://packages.gitlab.com/gitlab/gitlab-ce/install#manual

http://www.jianshu.com/p/a22eaa1fcfe7

11/07/2017 11:57 上午 posted in  Aliyun