SocketGCDAsyncSocket(异步Socket)

SocketGCDAsyncSocket(异步Socket)

2023年7月15日发(作者:)

SocketGCDAsyncSocket(异步Socket)Socket*********************************************简单理解Socket 就是⽹络连接,可以实现两个点之间的数据通讯。

•Socket允许使⽤长连接,允许应⽤程序运⾏在异步模式(提⾼效率),只有在需要的时候才接收数据

•使⽤Socket,可以只传送数据本⾝⽽不⽤进⾏XML封装,⼤⼤降低数据传输的开销 在(JSON)之前出现的iOS中常⽤的两种Socket类型

Ø流式Socket(SOCK_STREAM):流式是⼀种⾯向连接的Socket,针对于⾯向连接的TCP服务应⽤Ø数据报式Socket(SOCK_DGRAM):数据报式Socket是⼀种⽆连接的Socket,对应于⽆连接的UDP服务应⽤

•在iOS中以NSStream(流)来发送和接收数据开发步骤

{⽹络连接设置  1.设置⽹络连接,绑定到主机和端⼝  2.设置输⼊流和输出流的代理,监听数据流的状态  3.将输⼊输出流添加⾄运⾏循环  4.打开输⼊流和输出流发送消息给服务器有可读取字节时,读取服务器返回的内容到达流末尾时,关闭流,同时并从主运⾏循环中删除}

通过Scoket可以实现所有的⽹络功能:包括:GET、POST、PUT、DELETE⽂件读取、写⼊(I/O)⽅式是以(⼆进制)流的⽅式读取的 最主要的应⽤场景是:⾃定义的协议,编写⾃由的⽹络应⽤!

Socket 的难点: 1. 因为所有的(I/O)输⼊输出都是在⼀个代理⽅法中调⽤,随着⾃定义协议的复杂度的提⾼, 程序编写难度势必要⼤幅度提升。 2. 多线程的处理! 输⼊流和输出流都添加到了主运⾏循环,如果应⽤过于复杂,将影响主线程程序的性能 因此,需要使⽤另外⼀个运⾏循环,专门管理输⼊输出流。 代理⽅法的⼯作是对数据的输⼊输出流进⾏“解析”,解析⼯作同样不需要影响到主线程的⼯作。

3.多线程⽅⾯的处理,是Socket的⼀⼤难点!可以使⽤第三⽅框架GCDAsyncSocket来解决多线程问题。连接服务器#pragma mark 连接到服务器- (void)connectToServer:(NSString *)hostName port:(NSInteger)port{ // 设置⽹络 CFReadStreamRef readStream; CFWriteStreamRef writeStream;

// CF框架是C语⾔的框架 // 此⽅法可以连接到服务器,并分配输⼊流和输出流的内存空间 CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)hostName, port, &readStream, &writeStream);

// 记录已经分配的输⼊流和输出流 _inputStream = (__bridge NSInputStream *)readStream; _outputStream = (__bridge NSOutputStream *)writeStream;

// 设置代理,监听输⼊流和输出流中的变化 _te = self; _te = self; // Scoket是建⽴的长连接,需要将输⼊输出流添加到主运⾏循环 // 如果不将流加⼊主运⾏循环,delegate拒绝⼯作 [_inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; [_outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

// 打开输⼊流和输出流,准备开始⽂件读写操作 [_inputStream open]; [_outputStream open];} 登录到聊天室 1 #pragma mark 登录到聊天室 2 - (IBAction)login 3 { 4 NSString *hostName = _; 5 NSInteger port = [_ integerValue]; 6

7 [self connectToServer:hostName port:port]; 8

9 // 发送登录消息10 NSString *msg = [NSString stringWithFormat:@"iam:%@", _];11 // 在⽹络上发送的是⼆进制数据12 NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];13

14 // 发送数据,直接往输⼊流写数据15 [_outputStream write: maxLength:];16 } NSStream的代理⽅法/** NSStreamEventNone = 0, // ⽆事件 NSStreamEventOpenCompleted = 1UL << 0, // 建⽴连接完成 NSStreamEventHasBytesAvailable = 1UL << 1, // 有可读的字节,接收到了数据,可以读了 NSStreamEventHasSpaceAvailable = 1UL << 2, // 可以使⽤输出流的空间,此时可以发送数据给服务器 NSStreamEventErrorOccurred = 1UL << 3, // 发⽣错误 NSStreamEventEndEncountered = 1UL << 4 // 流结束事件,在此事件中负责做销毁⼯作 */#pragma mark NSStream的代理⽅法- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode{ NSLog(@"%d", eventCode);

switch (eventCode) { case NSStreamEventOpenCompleted: NSLog(@"连接完成"); break; case NSStreamEventHasBytesAvailable: NSLog(@"有可读字节"); // 读从服务器接收到得数据,从输⼊流中读取 // 先开辟⼀段缓冲区以读取数据,⽤空间来换取程序的简单 uint8_t buffer[1024];

// read返回的是输⼊流缓冲区中实际存储的字节数 NSInteger len = [_inputStream read:buffer maxLength:sizeof(buffer)];

if (len > 0) { // 读到数据 // 将buffer中的数据,转换成字符串,输出 NSString *str = [[NSString alloc] initWithBytes:buffer length:len encoding:NSUTF8StringEncoding];

// 将接收到的内容添加到数组 [_dataList addObject:str];

// 刷新表格 [_tableView reloadData]; }

break; case NSStreamEventHasSpaceAvailable: NSLog(@"可以写⼊数据"); break; case NSStreamEventErrorOccurred: NSLog(@"发⽣错误"); break; case NSStreamEventEndEncountered: NSLog(@"流结束"); // 做善后⼯作 // 关闭流的同时,将流从主运⾏循环中删除 [aStream close]; [aStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; default: break; }} GCDAsyncSocket(异步Socket)需要导⼊ork & ork框架// 1. Socket通讯的第⼀件事情——先创建⼀个长连接 _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];创建⼀个长连接 1 #pragma mark - Socket代理⽅法 2 #pragma mark 连接到主机 3 - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port 4 { 5 NSLog(@"连接建⽴ %@ %@", host, [NSThread currentThread]); 6

7 // 长连接建⽴完成后,给服务器发送 iam:昵称 通知服务器⽤户登录 8 NSString *str = [NSString stringWithFormat:@"iam:%@", _]; 9 // ⽹络通讯中,所有的数据都是以⼆进制流的模式传输的10 NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];11

12 // 将数据写⼊到输出流,告诉服务器⽤户登录13 [_socket writeData:data withTimeout:-1 tag:100];14 }15

16 #pragma mark 读数据17 - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag18 {19 NSString *str = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];20

21 if (tag == 100) {22 NSLog(@"登录消息 %@", str);23 } else {24 NSLog(@"聊天消息 %@->%ld", str, tag);25 }26

27 NSLog(@"%@", [NSThread currentThread]);28

29 // 剩下的⼯作 绑定表格数据30 [_dataList addObject:str];31

32 // 在主线程刷新表格33 dispatch_async(dispatch_get_main_queue(), ^{34 [_tableView reloadData];35 });36 }37

38 #pragma mark 写数据39 #pragma mark Socket已经把数据写给了服务器40 - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag41 {42 // 通过Log,我们发现在给服务器写⼊数据时,如果指定了tag,根据tag就知道发送(写给)的是哪⼀类的数据43 // 发现了读数据的代理⽅法没有被触发44 NSLog(@"写数据 %ld", tag);45

46 // 尝试让socket读⼀下数据,读取服务器返回的内容47 [_socket readDataWithTimeout:-1 tag:tag];48 }Socket代理⽅法 1 #pragma mark - Action 2 - (IBAction)connect:(id)sender 3 { 4 NSString *hostName = _; 5 int port = [[_portText text] intValue]; 6

7 // 连接到主机 8 NSError *error = nil; 9 if (![_socket connectToHost:hostName onPort:port error:&error]) {10 NSLog(@"%@", zedDescription);11 } else {12 NSLog(@"OK");13 }14 }Action

发布者:admin,转转请注明出处:http://www.yc00.com/web/1689407512a243110.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信