[Debug记录] 分布式实验-FTP编程
分布式课程学习JavaSocket和TCP/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端口来确保能被连接上。所以我的解决方案是在发送命令时给结尾附加一个端口参数,确保服务端可以明确需要向哪里发送文件。

浙公网安备 33010602011771号