在Mac OS中用Objective-C实现Telnet连接下本地及远端文件展示选择
Objective-C 实现 Telnet 连接下本地+远端文件浏览方案
1 本地 Mac 文件展示实现
本地文件浏览直接使用 Foundation 框架内置的 NSFileManager 即可完成,无需引入额外依赖:
- 核心调用
contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:API 遍历指定目录 - 沙箱权限说明:如果是上架 App Store 的应用,需要在
Signing & Capabilities中开启对应目录的File Access权限,测试阶段可临时关闭沙箱简化调试 - 示例代码:
NSURL *targetDir = [NSURL fileURLWithPath:NSHomeDirectory()]; NSFileManager *fm = [NSFileManager defaultManager]; NSError *error = nil; // 遍历目录,可通过option参数控制是否展示隐藏文件、是否遍历子目录 NSArray *fileList = [fm contentsOfDirectoryAtURL:targetDir includingPropertiesForKeys:@[NSURLNameKey, NSURLIsDirectoryKey, NSURLFileSizeKey] options:NSDirectoryEnumerationSkipsHiddenFiles error:&error]; if (fileList) { NSMutableArray *result = [NSMutableArray array]; for (NSURL *fileURL in fileList) { NSString *fileName; [fileURL getResourceValue:&fileName forKey:NSURLNameKey error:nil]; NSNumber *isDirectory; [fileURL getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:nil]; [result addObject:@{ @"name": fileName, @"isDir": isDirectory }]; } // 处理result数组渲染UI } else { NSLog(@"读取本地目录失败: %@", error.localizedDescription); }
2 Telnet 连接与远端文件展示实现
注意:Telnet 协议本身仅提供远程终端交互能力,没有内置文件浏览接口,所有远端文件信息都需要通过执行对应系统的 shell 命令、解析返回结果获取
2.1 核心实现逻辑
- 建立 TCP 连接到远端设备的 Telnet 端口(默认23)
- 处理 Telnet 协商选项(终端类型、回声设置等,避免返回内容乱码)
- 输入远端账号密码完成登录验证
- 发送对应系统的文件列表命令(Unix/Linux 用
ls -l,Windows 用dir) - 读取命令返回结果,解析为结构化的文件列表
2.2 代码示例
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> // 建立Telnet TCP连接 - (int)connectToServerWithIP:(NSString *)ip port:(uint16_t)port { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) return -1; struct sockaddr_in serverAddr; memset(&serverAddr, 0, sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(port); inet_pton(AF_INET, ip.UTF8String, &serverAddr.sin_addr); if (connect(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) { close(sockfd); return -1; } return sockfd; } // 发送命令并读取返回结果 - (NSString *)runCommand:(NSString *)command onSocket:(int)sockfd { // 补充换行符模拟终端输入 NSString *fullCmd = [command stringByAppendingString:@"\n"]; ssize_t sendLen = send(sockfd, fullCmd.UTF8String, fullCmd.length, 0); if (sendLen < 0) return nil; char buffer[1024]; NSMutableString *response = [NSMutableString string]; ssize_t recvLen; // 实际使用建议添加超时逻辑,避免长时间阻塞 while ((recvLen = recv(sockfd, buffer, sizeof(buffer)-1, 0)) > 0) { buffer[recvLen] = '\0'; [response appendString:[NSString stringWithUTF8String:buffer]]; // 检测到终端提示符则停止读取,可根据远端实际提示符调整匹配规则 if ([response rangeOfString:@"$ "].location != NSNotFound || [response rangeOfString:@"# "].location != NSNotFound || [response rangeOfString:@"> "].location != NSNotFound) { break; } } return response; } // 解析ls -l返回结果为文件列表(针对Unix/Linux远端) - (NSArray *)parseLsOutput:(NSString *)output { NSMutableArray *fileList = [NSMutableArray array]; NSArray *lines = [output componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet]; // 跳过第一行总用量提示 for (NSInteger i = 1; i < lines.count; i++) { NSString *line = lines[i].stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceCharacterSet; if (line.length < 10) continue; BOOL isDir = [line hasPrefix:@"d"]; // 按空格拆分字段,过滤空值 NSArray *components = [line componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceCharacterSet]; components = [components filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"length > 0"]]; if (components.count >= 9) { // 拼接带空格的文件名 NSString *fileName = [[components subarrayWithRange:NSMakeRange(8, components.count - 8)] componentsJoinedByString:@" "]; [fileList addObject:@{@"name":fileName, @"isDir":@(isDir)}]; } } return fileList; }
3 注意事项
- Telnet 是明文传输协议,账号密码和传输内容都可能被窃听,生产环境建议改用 SSH 协议替代
- 网络操作不要放在主线程执行,避免阻塞 UI,建议放到 GCD 后台队列处理
- 不同远端系统的命令返回格式差异较大,需要根据实际测试场景调整解析规则,正则匹配可以提升解析准确率
内容的提问来源于stack exchange,提问作者saravanar
相关产品推荐
相关产品推荐

