当前位置: 首页 > news >正文

[Debug记录] 分布式实验-FTP编程

分布式课程学习JavaSocketTCP/UDP,第一次实验要求基于Java Socket TCP和UDP实现一个简易的网络文件服务程序,包含服务器端FileServer和客户端FileClient。完成实验的过程中遇到一些比较典型的bug,记录一下。

用来结束多行响应的空行没有被读走

服务端发送响应的方法是这么写的

// 发送多行响应,最后以空行结束
private void sendMultiLine(String... lines) {for (String l : lines) writer.println(l);writer.println(); // 结束空行
}

而客户端我一开始是直接按行读取,遇到空行结束:

// 读取多行直到遇到空行
while (line = tcpReader.readLine()) != null && !line.isEmpty()) {sb.append(line).append('\n');line = tcpReader.readLine();
}

但这样写有时会有空行不能被正确读走,测试时输入了下一个命令才返回上一个命令的结果,显然是不对的。

最后在前面加上循环,每次读取时先把前面的空行读完再开始读内容

while ((line = tcpReader.readLine()) != null && line.isEmpty()) {// 跳过前导空行
}// 读取多行直到遇到空行
while (line != null && !line.isEmpty()) {sb.append(line).append('\n');line = tcpReader.readLine();
}

保存文件之前没有检查目录是否存在、文件名是否合法

使用get命令下载文件时直接写了这么一句,以项目路径+get的参数来作为下载路径

Path localFile = Paths.get(fileName).toAbsolutePath().normalize();

这里的问题有两个:

文件名不一定合法

前文对命令的校验只检查了命令本身是否合法,对应的文件存不存在是服务端考虑的时,就没有再考虑过,但是文件存在不代表命令参数中的fileName是合法的文件名。文件名参数有可能形如RelativeDir/fileName,此时相当于在项目目录下创建以此为名称的文件,显然是不可以的。

我的解决方案是在下载文件之前将参数fileName改为只保留文件名的形式

fileName = fileName.substring(fileName.lastIndexOf('/') + 1); 

下载路径不一定要放在项目目录,不应该写死,并且在设置下载路径时应该检查路径是否存在,如果不存在应该及时创建

我的解决方案是在构造函数中就将文件保存目录确定下来:

// 设置本地文件保存目录
localFileDir = Paths.get(".").toAbsolutePath().normalize().resolve("downloads");
System.out.println("本地文件保存目录: " + localFileDir);
if (!Files.exists(localFileDir)) {try {Files.createDirectories(localFileDir);} catch (IOException e) {System.err.println("无法创建本地文件保存目录: " + e.getMessage());}
}

客户端监听的端口和服务器监听的端口是两码事,不能搞混

服务端中设定好了TCP和UDP端口,但客户端程序编写时只留意设定了服务端的端口。

TCP还好,毕竟是双向连接,但UDP是单向的,服务器监听端口UDP_PORT和客户端监听的UDP端口是两码事。于是我的程序里服务端早早发完了文件,而客户端还阻塞在苦苦等待服务端的第一个分片。

但本地运行服务端是UDP_PORT是被占用的,而且客户端也不需要固定的UDP端口来确保能被连接上。所以我的解决方案是在发送命令时给结尾附加一个端口参数,确保服务端可以明确需要向哪里发送文件。

http://www.jsqmd.com/news/41934/

相关文章:

  • 2025年当下行业内知名的旧房翻新企业排名与推荐
  • 2025年国内旧房翻新公司综合实力排行榜TOP10推荐
  • 现今国内口碑好的旧房翻新企业排行
  • Linux服务器编程实践60-双向管道:socketpair函数的完成与应用场景
  • 前端从0到1实战】第3篇:拒绝插件,手写一个原生模态弹窗 (Modal)
  • 20232413 2025-2026-1 《网络与系统攻防技术》实验五实验报告
  • 循环数组下一个更大元素:从错误到精通(含2种解法+同类型扩展)
  • 实验四运行结果
  • 随机化数论算法总结
  • 20232422 2025-2026-1 《网络与系统攻防技术》实验五实验报告
  • 完整教程:【数据迁移】HBase Bulkload批量加载原理
  • 【AI智能体开发】什么是LLM?如何在本地搭建属于自己的Ai智能体? - 详解
  • 20232422 龙浩然 2025-2026-1 《网络与系统攻防技术》实验五实验报告
  • DL 1 深度学习简介 张量tensor操作
  • Spring Cloud Alibaba + RocketMQ
  • bpftrace报错:definitions.h:17:3: error: unknown type name pid_t
  • mybatis_generator
  • 目前市场口碑好的平移门服务商
  • [AGC030F]Permutation and Minimum
  • 2025年安徽伸缩门公司哪家权威:十大品牌综合评测
  • 脑机接口
  • 2025年11月阜阳伸缩门供应厂家有哪些
  • 【案例实战】多维度视角:鸿蒙2048游戏开发的深度分析与感悟 - 详解
  • 2025跨境物流/运输公司推荐:中亚/俄罗斯/阿富汗等线路最新top5口碑推荐
  • 2025年11月智能床垫品牌TOP5推荐:服务器系统软件办公深度集成
  • 2025年11月载冷剂厂家榜单:性能价格服务综合对比
  • Spring 中的 @Configuration 注解
  • PLUG2:STM32启动流程 - LI,Yi
  • C# 封装、继承、抽象、接口
  • python类中的__setattr__