Objective-C实现iOS端TCP/IP Socket收发文本功能求助
iOS Objective-C TCP Socket 收发文本分步实现指南
1 先明确现有代码的核心问题
- 仅创建了输出流,要接收服务端回复必须同时启用输入流
- 原有流代理方法收到任意事件就直接关闭流,导致后续无法执行读写操作,是首要需要修改的问题
- 不要用魔法数字代替
NSStreamEvent枚举值,降低代码可读性
2 第一步:补充类属性声明
在你当前类的@interface部分(.h文件或者类扩展中)补充以下属性:
@property (nonatomic, strong) NSOutputStream *outputStream; @property (nonatomic, strong) NSInputStream *inputStream; @property (nonatomic, strong) NSMutableData *receivedData; // 缓存收到的二进制数据 @property (nonatomic, strong) NSTimer *timer; @property (nonatomic, copy) NSString *LastMessage;
3 第二步:修改网络初始化方法
同时创建输入、输出流,修改后的initNetworkCommunication代码如下:
- (void)initNetworkCommunication { CFReadStreamRef readStream; CFWriteStreamRef writeStream; // 同时获取输入、输出流,不再给readStream传NULL CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.1.77", 5200, &readStream, &writeStream); self.inputStream = (__bridge NSInputStream *)readStream; self.outputStream = (__bridge NSOutputStream *)writeStream; // 两个流都设置代理,加入当前线程的RunLoop self.inputStream.delegate = self; self.outputStream.delegate = self; [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.inputStream open]; [self.outputStream open]; // 初始化接收数据缓存 self.receivedData = [NSMutableData data]; self.timer = [NSTimer scheduledTimerWithTimeInterval:1.5 target:self selector:@selector(SocketFail) userInfo:nil repeats:NO]; }
4 第三步:重写流事件代理方法
删掉原来一进入代理就关流的逻辑,分事件类型处理:
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent { switch (streamEvent) { case NSStreamEventOpenCompleted: // 流打开成功,关闭超时定时器 [self.timer invalidate]; self.timer = nil; self.LastMessage = @"Connected"; // 连接成功后可直接调用发送方法,也可以按需在其他时机调用 // [self sendText:@"你需要发送的单行文本"]; break; case NSStreamEventHasBytesAvailable: // 有数据可读,处理接收逻辑 if (theStream == self.inputStream) { uint8_t buffer[1024]; NSInteger readLength = [self.inputStream read:buffer maxLength:sizeof(buffer)]; if (readLength > 0) { // 把读到的数据追加到缓存 [self.receivedData appendBytes:buffer length:readLength]; // 按单行文本的约定,用换行符做分隔判断是否收到完整回复 NSString *receivedStr = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; if ([receivedStr containsString:@"\n"]) { // 拆分出有效回复,去掉换行符 NSString *reply = [receivedStr stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; // 此处写你对回复的解析逻辑 NSLog(@"收到完整回复:%@", reply); // 处理完清空缓存,可根据你的业务协议调整处理逻辑 [self.receivedData resetBytesInRange:NSMakeRange(0, self.receivedData.length)]; self.receivedData.length = 0; } } } break; case NSStreamEventErrorOccurred: // 连接出错 self.LastMessage = @"连接出错"; NSLog(@"流错误:%@", theStream.streamError); [self closeStream]; break; case NSStreamEventEndEncountered: // 流结束,对端关闭连接 [self closeStream]; break; default: break; } }
5 第四步:添加发送文本和统一关闭流的工具方法
// 发送单行文本方法 - (void)sendText:(NSString *)text { // 给文本加换行符,和服务端约定好单行内容的分隔标识 NSString *sendStr = [text stringByAppendingString:@"\n"]; NSData *sendData = [sendStr dataUsingEncoding:NSUTF8StringEncoding]; if (!self.outputStream.hasSpaceAvailable) { NSLog(@"当前流不可写,发送失败"); return; } NSInteger writeLength = [self.outputStream write:sendData.bytes maxLength:sendData.length]; if (writeLength < 0) { NSLog(@"发送失败,错误:%@", self.outputStream.streamError); } else if (writeLength < sendData.length) { // 单次写入未发完的场景,简单需求可暂不处理,复杂场景建议添加待发送缓存,下次收到NSStreamEventHasSpaceAvailable事件时继续发送剩余数据 NSLog(@"部分数据未发送完成"); } else { NSLog(@"文本发送成功"); } } // 统一关闭流的公共方法 - (void)closeStream { [self.inputStream close]; [self.outputStream close]; [self.inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; [self.outputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; self.inputStream = nil; self.outputStream = nil; } // 原有超时方法适配调整 - (void)SocketFail { [self closeStream]; [self.timer invalidate]; self.timer = nil; self.LastMessage = @"Could not connect"; }
6 调用逻辑说明
- 先调用
initNetworkCommunication触发Socket连接 - 收到
NSStreamEventOpenCompleted事件确认连接成功后,调用sendText方法发送你需要的文本即可 - 服务端返回的回复会在
NSStreamEventHasBytesAvailable的处理逻辑中返回,直接在对应位置补充你的解析逻辑即可
内容的提问来源于stack exchange,提问作者Jill_NYC
相关产品推荐
相关产品推荐

