赞
踩
目录
前言:本篇文章不提供知识点教学,只提供一些常见问题的解决方法和实现实验要求的学习路径
3.1.1 服务器端作为发送端,客户端作为接收端
3.1.1.1 问题分解
指定...
关于服务器端如何获取客户端的host和port:
已否决:通过客户端连接
// connect():连接UDP客户端和UDP服务器端 dgSocket = new DatagramSocket(); // 随机可用端口,又称匿名端口 dgSocket.connect(new InetSocketAddress(HOST, UDP_PORT));
尝试:UDP客户端发送一份数据给UDP服务器端,通过dp.getAddress()和dp.getPort()获取UDP客户端的端口号
3.1.1.2 关键问题
问题1:指定文件的大小(其实没必要,不用指定文件大小,每次按固定的大小循环传输直到传完所有的数据即可)
问题如下图所示:
服务器端代码:
pw.println("文件大小:" + is.available() + " bytes"); // 告诉客户端要接收的文件的大小(单位:byte)
客户端代码:
int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte)
由于输入不是纯数字,因此String不能顺利转换为int
解决方案:
// 预定义 bw = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream())); // 服务器端 is = new FileInputStream(new File(BASE_PATH + fileName)); byte[] b = new byte[is.available()]; System.out.println(is.available()); pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte)
// 预定义 br = new BufferedReader(new InputStreamReader( socket.getInputStream())); // 客户端 int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte) System.out.println("文件大小为:" + length + " bytes"); byte[] b = new byte[length];
问题2:文件过大,不能一次传输完
问题描述:
解决方案:分段传输
代码如下:
// 服务器端 is = new FileInputStream(new File(BASE_PATH + fileName)); pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte) byte[] b = new byte[BYTE_LEN]; // 创建UDP数据报 while (is.read(b) != -1) { DatagramPacket dp = new DatagramPacket(b, b.length, socketAddress); dgSocket.send(dp); System.out.println("传输文件中..."); TimeUnit.MICROSECONDS.sleep(100); // 限制传输速度 } System.out.println("文件发送成功");
// 客户端 os = new FileOutputStream(new File(BASE_PATH + fileName)); byte[] b = new byte[BYTE_LEN]; DatagramPacket dp = new DatagramPacket(b, b.length); int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte) while (length > 0) { // 接收数据 dgSocket.receive(dp); os.write(b, 0, b.length); os.flush(); System.out.println("接收文件中..."); length -= BYTE_LEN; }
问题3:文件名输入错误(系统在该目录下找不到该文件),未使用try catch语句捕捉错误
问题描述:
解决方案:
// 服务器端 try { is = new FileInputStream(new File(BASE_PATH + fileName)); } catch(FileNotFoundException e) { System.out.println("不存在该文件,取消文件传输"); pw.println("不存在该文件,取消文件传输"); e.printStackTrace(); return; }
if( br.readLine().equals("不存在该文件,取消文件传输") ) { System.out.println("取消文件传输,结束本次通信"); return; } else { System.out.println("文件已验证存在"); }
衍生问题:由于已经调用过一次br.readLine(),后面又通过br.readLine()获取文件长度。而readLine()会移动读取指针,且服务器端只传了一次length(通过pw.println(is.available());),因此在第二次调用br.readLine()的时候,客户端获取的内容为空,导致线程阻塞,文件传输不能正常进行。
解决方案:
// 预定义 PrintWriter pw = new PrintWriter(bw, true); // 服务器端 // 传两次,因为客户端br.readLine()使用了两次【readLine()函数使用一次会移动读取指针】 pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte) pw.println(is.available()); // 告诉客户端要接收的文件的大小(单位:byte)
// 预定义 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); // 客户端 if( br.readLine().equals("不存在该文件,取消文件传输") ) { System.out.println("取消文件传输,结束本次通信"); return; } else { System.out.println("文件已验证存在"); } int length = Integer.parseInt(br.readLine()); // 获取服务器端传来的文件的大小(单位:byte)
问题4:
3.1.2 客户端作为发送端,服务器端作为接收端
1) 复习Java I/O和Socket编程相关概念和方法;
2) 基于Java Socket TCP和UDP实现一个简易的网络文件服务程序,包含服务器端FileServer和客户端FileClient;
3) 服务器端启动时需传递root目录参数,并校验该目录是否有效;
4) 服务器启动后,开启TCP:2021端口,UDP:2020端口,其中,TCP连接负责与用户交互,UDP负责传送文件;
5) 客户端启动后,连接指定服务器的TCP 2021端口,成功后,服务器端回复信息:“客户端IP地址:客户端端口号>连接成功”;
6) 连接成功后,用户可通过客户端命令行执行以下命令:
*[1] ls* 服务器返回当前目录文件列表(<file/dir> name size)
*[2] cd * 进入指定目录(需判断目录是否存在,并给出提示)
*[3] get * 通过UDP下载指定文件,保存到客户端当前目录下
*[4] bye* 断开连接,客户端运行完毕
7) 服务器端支持多用户并发访问,不用考虑文件过大或UDP传输不可靠的问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。