You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 18:39:03