本文为小学期课程设计,为方便日后查阅,在此总结。
在本次设计中我们选择流式套接字搂完成C/S模式的通信,保证数据能够准确、无误的传输。下图所示的是流式套接字的基本通信方式。
CalcLen.java //计算文件长度 CalcMD5.java //计算文件MD5值 FileTransferClient.java //客户端 FileTransferServer.java //用户端
public class CalcLen { public static DecimalFormat df = null; static { // 设置数字格式,保留一位有效小数 df = new DecimalFormat("#0.0"); df.setRoundingMode(RoundingMode.HALF_UP); df.setMinimumFractionDigits(1); df.setMaximumFractionDigits(1); } public static String getFormatFileSize(long length) { double size = ((double) length) / (1 << 30); if(size >= 1) { return df.format(size) + "GB"; } size = ((double) length) / (1 << 20); if(size >= 1) { return df.format(size) + "MB"; } size = ((double) length) / (1 << 10); if(size >= 1) { return df.format(size) + "KB"; } return length + "B"; } } public class CalcMD5 { private static final char[] hexCode = "0123456789ABCDEF".toCharArray(); /** * 测试MD5函数的正确性 */ // public static void main(String[] args) { // long beginTime = System.currentTimeMillis(); // File file = new File("D:\\test.txt"); // // String md5 = calc(file); // long endTime = System.currentTimeMillis(); // System.out.println("MD5:" + md5 + "\n 耗时:" + ((endTime - beginTime) / 1000) + "s"); // } /** * 计算文件 MD5 * * @param file * @return 返回文件的md5字符串,如果计算过程中任务的状态变为取消或暂停,返回null, 如果有其他异常,返回空字符串 */ public static String calc(File file) { try (InputStream stream = Files.newInputStream(file.toPath(), StandardOpenOption.READ)) { MessageDigest digest = MessageDigest.getInstance("MD5"); byte[] buf = new byte[8192]; int len; while ((len = stream.read(buf)) > 0) { digest.update(buf, 0, len); } return toHexString(digest.digest()); } catch (IOException e) { e.printStackTrace(); return ""; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return ""; } } /** * 工具函数:用于计算哈希值 * @param data * @return hexCode */ public static String toHexString(byte[] data) { StringBuilder r = new StringBuilder(data.length * 2); for (byte b : data) { r.append(hexCode[(b >> 4) & 0xF]); r.append(hexCode[(b & 0xF)]); } return r.toString(); } } public class FileTransferClient { private String host = "localhost"; private int port = 8888; private Socket socket; private static String fileName = "D:\\test.txt"; /** * 设置无参构造方式 * @throws IOException */ public FileTransferClient() throws IOException { socket = new Socket(host, port); } /** * 有参构造方式 * @param host * @param port * @throws IOException */ public FileTransferClient(String host ,int port) throws IOException{ this.host = host; this.port = port; socket = new Socket(host, port); } /** * 发送文件方法 * * @param filePath */ public void sendFile(String filePath) { try { File file = new File(filePath); DataInputStream dis = new DataInputStream(new FileInputStream(filePath)); DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); System.out.println("现在开始发送文件:" + file.getName() + "。"); dos.writeUTF(file.getName());//先传入名字进Socket dos.flush(); dos.writeLong(file.length());//传入文件长度 dos.flush(); String MD5 = CalcMD5.calc(file); dos.writeUTF(MD5);//传入文件MD5 System.out.println("发送文件的MD5为:" + MD5); dos.flush(); byte[] buf = new byte[1024 * 9]; long progress = 0;//显示文件传输进展 int len = 0; while ((len = dis.read(buf)) != -1) { dos.write(buf, 0, len); progress += len; System.out.print("| " + (100*progress/file.length()) + "% |"); } dos.flush(); System.out.println("文件:" + file.getName() + "发送成功,大小为:" + CalcLen.getFormatFileSize(file.length()) + "。"); dis.close(); dos.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 测试客户端发送方法 * @param args * @throws IOException */ public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); System.out.println("**文件传输系统-客户端**"); String host; File file; int flag; int port; String ipReg = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"; Pattern ipPattern = Pattern.compile(ipReg);//校验是否为ip地址 do { System.out.print("目标IP:"); host = sc.nextLine(); if(!ipPattern.matcher(host).matches()) { System.out.println("输入错误,请重输。"); } }while(!ipPattern.matcher(host).matches()); do { System.out.print("目标端口:"); port = sc.nextInt(); if(!(port > 0 && port < 65535)) { System.out.println("输入错误,请重输。"); } }while(!(port > 0 && port < 65535)); do { do { System.out.print("发送文件:"); fileName = sc.next(); file = new File(fileName); if (!file.isFile()) { System.out.println("输入错误,请重输。"); } } while (!file.isFile()); new FileTransferClient(host, port).sendFile(fileName); System.out.println("是否需要继续传输文件? 1:是 0:不是"); flag = sc.nextInt(); }while(flag == 1); System.out.println("已退出,感谢使用!"); } } public class FileTransferServer { private int port = 8888; //端口名 private ServerSocket serverSocket; //服务端socket private DataInputStream dis; private FileOutputStream fos; Socket socket; /** * 无参构造 * @throws IOException */ public FileTransferServer() throws IOException { //构造函数 serverSocket = new ServerSocket(port); System.out.println("服务器已经启动。"); System.out.println("正在等待客户端的连接。"); } public FileTransferServer(int port) throws IOException{ serverSocket = new ServerSocket(port); System.out.println("服务器已启动。"); System.out.println("正在等待客户端的连接。"); } public void receieveFile(String filePath) { while (true) { try { socket = serverSocket.accept(); System.out.println("已接收到客户端的连接。"); dis = new DataInputStream(socket.getInputStream()); File diretory = new File(filePath); String fileName = dis.readUTF(); long fileLength = dis.readLong(); String MD5 = dis.readUTF(); if(!diretory.exists()){ diretory.mkdirs(); } System.out.println("现在开始接收文件: " + fileName + " ,文件MD5为: " + MD5); File file = new File(diretory.getAbsolutePath() + File.separator + fileName); fos = new FileOutputStream(file); byte[] buf = new byte[1027 * 9]; int len = 0; long progress = 0;//显示文件传输进展 while ((len = dis.read(buf)) != -1) { fos.write(buf, 0, len); fos.flush(); progress += len; System.out.print("| " + (100*progress/file.length()) + "% |"); } System.out.println("文件接受成功" + fileName + "大小为:" + CalcLen.getFormatFileSize(fileLength)); String MD5Test = CalcMD5.calc(file); System.out.println("计算文件得到的MD5为:" + MD5Test); if(MD5.equals(MD5Test))//将接受到的MD5与发送过来的MD5进行对比 { System.out.println("MD5与接收到的MD5相等,文件传输完整。"); } else { System.out.println("MD5与接收到的MD5不等,文件传输出错."); } System.out.println("继续等待客户端的连接。"); } catch (IOException e) { e.printStackTrace(); } finally { try { if(fos != null) fos.close(); if(dis != null) dis.close(); socket.close(); } catch (Exception e) {} } } } public static void main(String[] args) throws IOException { Scanner sc = new Scanner(System.in); System.out.println("**文件传输系统-用户端**"); int port; String fileName; File file; do { System.out.print("开放端口为:"); port = sc.nextInt(); if(!(port > 0 && port < 65535)) { System.out.println("输入错误,请重输。"); } }while(!(port > 0 && port < 65535)); do { System.out.print("接收文件目录:"); fileName = sc.next(); file = new File(fileName); if(!file.isDirectory()) { System.out.println("输入路径不为目录,请重输。"); } }while(!file.isDirectory()); new FileTransferServer(port).receieveFile(fileName); } }
如果能对你有一点点帮助的话就我就很开心了。