Socket通信

来源:互联网 发布:孙中山萝莉控 知乎 编辑:程序博客网 时间:2024/06/05 10:32

1、连接服务器

- (void)connect {

    CFReadStreamRef readStream;

    CFWriteStreamRef writeStream;

    CFStreamCreatePairWithSocketToHost(NULL, (__bridgeCFStringRef)self.address, (UInt32)self.port, &readStream, &writeStream);

    self.inputStream = (__bridgeNSInputStream *)readStream;

    self.outputStream = (__bridgeNSOutputStream *)writeStream;

    CFRelease(readStream);

    CFRelease(writeStream);

    

    // 添加到当前的RunLoop

    [self.inputStreamsetDelegate:self];

    [self.outputStreamsetDelegate:self];

    [self.inputStreamscheduleInRunLoop:[NSRunLoopcurrentRunLoop]forMode:NSDefaultRunLoopMode];

    [self.outputStreamscheduleInRunLoop:[NSRunLoopcurrentRunLoop]forMode:NSDefaultRunLoopMode];

    

    // 打开流

    isInputOpenCompleted =NO;

    isOutputOpenCompleted =NO;

    [self.inputStreamopen];

    [self.outputStreamopen];

}


- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {

switch (eventCode) {

caseNSStreamEventOpenCompleted: {

[selfsendHandShakePacketFirst]; // 发送第一次握手包

}

caseNSStreamEventHasBytesAvailable:{

            DebugLog(@"have Byte to read");

            [selfreadData];

       }

            break;

        caseNSStreamEventHasSpaceAvailable:{

            DebugLog(@"have space to write");

            [selfwriteData];

}

break;

}

}


2、 发送第一次握手包

- (void)sendHandShakePacketFirst {

    BBPacket *packet = [[BBPacketalloc]initWithFlag:CTFlagConnectStatusHandShakeFirst];

    packet.bbCommand = [[BBHandShakeCommandalloc]initWithFlag:CTFlagConnectStatusHandShakeFirst];

    [selfsendPacket:packet];

}

/*!

 发送一个命令包

 @param packet 要发送的命令包

 */

- (void)sendPacket:(BBPacket *)packet {

[selfwriteData];

}


3、写数据

/*!

 写入要发送的数据

 */

- (void)writeData {

    NSData *data =nil;

    NSUInteger packetIndex =0;

    if ([self.bbDelegaterespondsToSelector:@selector(connectionSendData:packetIndex:)]) {

        data = [self.bbDelegateconnectionSendData:selfpacketIndex:&packetIndex];

    }

    

    while (([self.outputStreamhasSpaceAvailable]) && ([data length] > 0)) {

        NSInteger bytesWritten = [self.outputStreamwrite:[databytes]maxLength:[datalength]];


        if (bytesWritten == -1)

        {

            DebugLog(@"write error");

            if ([self.bbDelegaterespondsToSelector:@selector(connectionSendDataFailed:packetIndex:)]) {

                [self.bbDelegateconnectionSendDataFailed:selfpacketIndex:packetIndex];

            }

            break;

        }

        elseif (bytesWritten >0)

        {

            if ([self.bbDelegaterespondsToSelector:@selector(connectionSendDataSucceed:packetIndex:)]) {

                [self.bbDelegateconnectionSendDataSucceed:selfpacketIndex:packetIndex];

            }

            break;

        }

    }

    

    data = nil;

}


4、读数据

/*!

 分发处理一个数据包

 */

- (void)dispatchPacket:(BBPacket *)packet {

    BBPacketHead *packetHead = packet.bbPacketHead;

    switch (packetHead.ctFlag) {

        caseCTFlagConnectStatusHandShakeSecond: {

[selfsendHandShakePacketThird:shakeKeyData];

}

break;

caseCTFlagConnectStatusHandShakeFourth: {

//- (void)startKeepAlive:(BBHandShakeCommand *)handShakeCommand;

}

}

}

5、依次进行第2、3、4次握手


第二次握手时,使用本地预存的8对RSA公钥中的一个解密服务传回的数据。

第三次握手时,使用服务传回的公钥加密本地新生成的RSA公钥。传给服务器,服务器会使用上传的公钥加密AES密钥。

第四次握手时,使用前面生成的RSA私钥解密服务器传回的AES密钥

握手完成后,将进入正常的会话流程同时开始心跳包的发送,

对于上行的数据需要加密并压缩,加密使用AES的PKCS7Padding加密方式,压缩使用zip压缩,

服务器返回的数据是加密的但不一定是压缩的,服务器加密使用ECBMode加密方式,

压缩时使用gZip压缩(目前测试发现当网民端发送1000字节长试的消息时,服务会压缩数据)。


6、第4次握手完成后,开始发送心跳包

/*!

 开始心跳

 */

- (void)startKeeyAlive {

    if (self.keepAliveTimer) {

        [self.keepAliveTimerinvalidate];

        self.keepAliveTimer =nil;

    }

    self.keepAliveTimer = [NSTimerscheduledTimerWithTimeInterval:self.signIntervaltarget:selfselector:@selector(handleTimer)userInfo:nilrepeats:YES];

    [self.keepAliveTimerfire];

}

- (void)handleTimer {

[selfsendPacket:packet];

}


以下是socket步骤的枚举标记:

/*!

 定义会话阶段标记

 */

typedef NS_ENUM(UInt32, CTFlagConnectStatus) {

    /*!

     会话第一步(握手)

     */

    CTFlagConnectStatusHandShakeFirst = 0,

    /*!

     会话第二步(握手)

     */

    CTFlagConnectStatusHandShakeSecond = 1,

    

    /*!

     会话第三步(握手)

     */

    CTFlagConnectStatusHandShakeThird = 2,

    

    /*!

     会话第四步(握手)

     */

    CTFlagConnectStatusHandShakeFourth = 3,

    

    /*!

     心跳包

     */

    CTFlagConnectStatusKeepAlive = 37,

    

    /*!

     心跳包的响应包

     */

    CTFlagConnectStatusKeepAliveResponse = 47,

    

    /*!

     会话进入正常流程

     */

    CTFlagConnectStatusConversiationOk = 31,

    

    /*!

正常会话-不加密-不压缩

     */

    CTFlagConnectStatusNoAesNoZip = 7,

    

    /*!

正常会话-加密-不压缩

     */

    CTFlagConnectStatusDoAesNoZip = 15,

    

    /*!

正常会话-不加密-压缩

     */

    CTFlagConnectStatusNoAesDoZip = 23,

    

    /*!

     进入后台

     */

    CTFlagConnectStatusEnterBackground = 64,

    

    /*!

     进入后台响应

     */

    CTFlagConnectStatusEnterBackgroundResponse = 128,

    

    /*!

     进入前台

     */

    CTFlagConnectStatusEnterForeground = 256,

    

    /*!

     进入前台响应

     */

    CTFlagConnectStatusEnterForegroundResponse = 512,

    

    /*!

     被代理服务器踢出

     */

    CTFlagConnectStatusKickedoutProxy = 1024,

};

0 0
原创粉丝点击