美文网首页
《为了让你变得更强壮》技术支持网址

《为了让你变得更强壮》技术支持网址

作者: iceBridge | 来源:发表于2019-07-10 21:06 被阅读0次

    要调试socket,首先应该有一个简易的socket服务端,下面是用python写的简单服务端,功能是发送iam:name相当于登录操作,服务器会返回name has joined,发送msg:content,服务器会判断当前登录者,然后返回name:msg。

    下面是server.py的源码 -参考

    fromtwisted.internet.protocolimportProtocol, Factoryfromtwisted.internetimportreactorclassIphoneChat(Protocol):defconnectionMade(self):self.transport.write("""connected""")            self.factory.clients.append(self)print"clients are ",      self.factory.clientsdefconnectionLost(self, reason):self.factory.clients.remove(self)defdataReceived(self, data):data a = data.split(':')iflen(a) >1:                    command = a[0]                    content = a[1]                                msg =""ifcommand =="iam":                        self.name = content                        msg = self.name +" has joined"elifcommand =="msg":                        msg = self.name +": "+ contentprintmsgforcinself.factory.clients:                        c.message(msg)defmessage(self, message):self.transport.write(message +'/n')    factory = Factory()    factory.protocol = IphoneChat    factory.clients = []reactor.listenTCP(12345, factory)print"IphoneChat server started"reactor.run()

    使用方法也很简单,只需要打开终端,输入python server.py即可运行服务端,运行成功后会在终端打印Iphone Chat server started.

    下面介绍如何实现iOS客户端:

    从上面的源码可以看到,服务端的端口号是12345,假设是在本地使用,则按如下方法进行连接:

    // 建立连接 NSString *host = @"127.0.0.1"; int port = 12345; // 注意C字符串和OC字符串桥接转换// 定义输入输出流 CFReadStreamRefread_s;CFWriteStreamRefwrite_s;CFStreamCreatePairWithSocketToHost(NULL, (__bridgeCFStringRef)host, port, &read_s, &write_s);

    注意CF开头的是C语言的结构体和函数,为了和OC连接,我们需要定义OC的输入输出流:

    NSInputStream*_input_s;NSOutputStream*_output_s;

    然后进行桥接转换:不要忘记设置代理,OC的输入输出流有数据时通过代理来通知。

    // 使用代理来通知连接建立是否成功,把C语言的输入输出流转化成OC对象,使用桥接转换。_input_s = (__bridgeNSInputStream*)(read_s); _output_s = (__bridgeNSOutputStream*)(write_s); _input_s.delegate = _output_s.delegate =self;

    Tip:流的代理名称为NSStreamDelegate。

    之后不要忘记将流加入到主运行循环,并且打开流:

    // 把输入输出流添加到主运行循环,否则代理可能不工作[_input_s scheduleInRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];  [_output_s scheduleInRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];// 打开输入输出流[_input_s open]; [_output_s open];

    在连接结束时时,不要忘记把流从主循环上移除,判断连接状态通过NSStream的代理方法:

    - (void)stream:(NSStream*)aStream handleEvent:(NSStreamEvent)eventCode{switch(eventCode) {caseNSStreamEventEndEncountered:{// 连接结束 NSLog(@"关闭输入输出流");[_input_s close]; [_output_s close]; [_input_s removeFromRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];  [_output_s removeFromRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];break; }caseNSStreamEventErrorOccurred:// 连接出错 break;caseNSStreamEventHasBytesAvailable:// 有字节可读[selfreadData];break;caseNSStreamEventNone:// 无事件 break;caseNSStreamEventOpenCompleted:// 连接打开完成 NSLog(@"打开完成"); break;caseNSStreamEventHasSpaceAvailable:// 可以发放字节break;default:break; } }

    建立连接的完整代码为:

    // 建立连接 NSString*host =@"127.0.0.1";intport =12345;// 注意C字符串和OC字符串桥接转换 // 定义输入输出流 CFReadStreamRefread_s;CFWriteStreamRefwrite_s;CFStreamCreatePairWithSocketToHost(NULL, (__bridgeCFStringRef)host, port, &read_s, &write_s);//代理来通知连接建立是否成功,把C语言的输入输出流转化成OC对象,使用桥接转换。 _input_s = (__bridgeNSInputStream*)(read_s); _output_s = (__bridgeNSOutputStream*)(write_s); _input_s.delegate = _output_s.delegate =self;// 把输入输出流添加到主运行循环,否则代理可能不工作 [_input_s scheduleInRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode]; [_output_s scheduleInRunLoop:[NSRunLoopmainRunLoop] forMode:NSDefaultRunLoopMode];// 打开输入输出流 [_input_s open]; [_output_s open];

    想要发送一条消息,只需要通过OC的输出流即可,先把NSString转化为data,然后调用流的write方法,注意这里需要传两个参数,一个是缓冲区大小,一个是最大长度:data.bytes返回的是一个很大的值,而data.length返回的是实际长度,因此我们用data.bytes作为缓冲区的大小,data.length作为实际长度。

    // 发送 iam:name 表示name登录 NSString*loginStr =@"iam:soulghost";// 把string转成NSData NSData*data = [loginStr dataUsingEncoding:NSUTF8StringEncoding]; [_output_s write:data.bytes maxLength:data.length];

    一旦我们收到数据,就会调用上面提到的代理方法,通过eventCode区分(上面用代理方法处理了连接成功和连接结束),如果eventCode为NSStreamEventHasBytesAvailable,代表有字节可读,这时候我们需要一个方法来读取输入流的内容:

    // 建立一个缓冲区,可放1024字节 uint8_t buf[1024];NSIntegerlen = [_input_s read:buf maxLength:sizeof(buf)];// 把字节数组转化为字符串 NSData*data = [NSDatadataWithBytes:buf length:len];NSString*msg = [[NSStringalloc] initWithData:data encoding:NSUTF8StringEncoding];

    输入流的内容会存到unsigned char数组内,uint8_t即unsigned char,我们定义1024字节的缓冲区,接收从输入流中读到的数据,然后用它来初始化一个data,转为字符串后处理。

    作者:WildDylan

    链接:https://www.jianshu.com/p/3d32d2392905

    来源:简书

    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

    相关文章

      网友评论

          本文标题:《为了让你变得更强壮》技术支持网址

          本文链接:https://www.haomeiwen.com/subject/upbkkctx.html