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;
}
/*!
分发处理一个数据包
*/
- (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,
};
- Socket通信
- Socket通信
- socket通信
- Socket通信
- Socket通信
- socket通信
- socket通信
- socket通信
- socket 通信
- socket通信
- SOCKET通信
- Socket通信
- 通信 socket
- socket 通信
- socket通信
- socket通信
- socket通信
- socket通信
- docker
- 百练:1007 装箱问题
- 理解 Linux 的硬链接与软链接
- flume学习(一):log4j直接输出日志到flume
- vc枚举所有可用的端口号
- Socket通信
- CODE的基础使用
- MIME 类型(HttpContext.Response.ContentType)列表[转]
- solr教程,值得刚接触搜索开发人员一看
- 10个学习Android开发的网站推荐
- robots协议
- wireshark使用教程
- 【服务器配置】php move_uploaded_file文件移动失败
- MFC六大核心机制之三:动态创建