java实现TCP与UDP混合传输文件总结
最近在用java写基于UDP传输文件的网络,遇到了很多问题,也参考了很多人编写的程序,通过 自己的整理和设计,终于写完了自己程序,现在将在编程中遇到的问题总结一下。
发送方:
首先发送方需要发送文件的一些属性给文件接收方,如文件的名称,文件的大小等,让文件接收方判断是否接受文件,由于这部分内容比较重要,不能出现丢包的现象,所以采用TCP/IP协议来传输文件,而在文件传输的时候,我们采用UDP协议传输,这样能让文件传输得更快。先看一下发送方代码。
import java.awt.*; import java.io.*; import java.net.*; import java.util.*; import java.util.concurrent.TimeUnit; import javax.swing.*; public class FileClient extends JFrame { FileDialog fd1 = null; DatagramSocket ds = null; DatagramPacket sendDp = null; static int sendDataLen = 10240; public byte[] sendBuff = new byte[sendDataLen]; public InetAddress udpIP = null; static int udpPort = 10000; static int tcpPort = 9999; public static void main(String[] args) { // TODO Auto-generated method stub FileClient fc = new FileClient(); fc.fileSender(); } public void fileSender() { try { // 打开windows的文件对话框 fd1 = new FileDialog(this, "请选择需要打开的文件", FileDialog.LOAD); fd1.setVisible(true); String filePath = fd1.getDirectory() + fd1.getFile(); String location = filePath.replaceAll("\\\\", "/"); System.out.println("绝对文件目录+文件名" + filePath); System.out.println("绝对文件目录+文件名" + location); DataInputStream dis = new DataInputStream(new BufferedInputStream( new FileInputStream(location))); // 单位是字节 int fileLen = dis.available(); System.out.println("文件长度" + fileLen); // **************************************************** // 写一个TCP协议发送文件标题,让接受端确认是否接受 Socket s = new Socket("127.0.0.1", tcpPort);// 发送到本机 PrintWriter pw = new PrintWriter(s.getOutputStream(), true); String headInfo = fd1.getFile() + "/" + fileLen; pw.println(headInfo); // 等待对方确认 InputStreamReader isr = new InputStreamReader(s.getInputStream()); BufferedReader br = new BufferedReader(isr); // 阻塞等待 String info = br.readLine(); System.out.println("我接收到文件接收器给我返回的内容了=" + info); if (info.equals("YES")) { s.close(); System.out.println("我是文件发送器UDP,我已经开始发送了"); // 主机从任意空闲端口发送; ds = new DatagramSocket(); udpIP = InetAddress.getByName("127.0.0.1"); while (dis.read(sendBuff) > 0) { sendDp = new DatagramPacket(sendBuff, sendBuff.length, udpIP, udpPort); ds.send(sendDp); TimeUnit.MICROSECONDS.sleep(1);// 限制传输速度 // ****************************************** } } else { JOptionPane.showMessageDialog(null, "对方拒绝接受文件", "消息提示", JOptionPane.WARNING_MESSAGE); dis.close(); s.close(); } System.out.println("发送完毕"); dis.close(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
接收方(有一个确认接对话框类):
package com.tcpip.model; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.net.*; import javax.swing.*; public class FileReceiver { static final int receivePort = 10000; DatagramPacket receiveDp = null; DatagramSocket receiveDs = null; int dataLen = 10240; public byte[] inBuff = new byte[dataLen]; String filePath = null; InetAddress clientIp = null; String myUserId = "小富"; public static void main(String[] args) { // TODO Auto-generated method stub FileReceiver fr = new FileReceiver(); fr.fileReceiver(); } public void fileReceiver() { try { // 写一个TCP接收协议,判断是否接受对方发过来的信息 ServerSocket ss = new ServerSocket(9999); // 阻塞,等待接收 Socket s = ss.accept(); PrintWriter pw = new PrintWriter(s.getOutputStream(), true); // 读取客户端信息 InputStreamReader isr = new InputStreamReader(s.getInputStream()); BufferedReader br = new BufferedReader(isr); // 阻塞,等待接收从缓存中读取 String fileInfo = br.readLine(); String headInfomation[] = fileInfo.split("/"); String fileName = headInfomation[0]; String fileLen0 = headInfomation[1]; System.out.println("tcp接受到的内容为=" + headInfomation[0]); System.out.println("tcp接受到的内容为=" + headInfomation[1]); int fileLen = Integer.parseInt(fileLen0); // 显示面板,显示对方发过来的文件信息,文件名称及文件大小,并确定是否收文件 ReceiveConfirm rc = new ReceiveConfirm(myUserId, fileName, fileLen); String wait = rc.getLocationpath(); // 等待存储文件的路径的产生 while (wait.equals("wait")) { wait = rc.getLocationpath(); System.out.println("我在这儿等待接收存储方的文件目录"); } String headInfo = "YES"; pw.println(headInfo); ss.close(); String filePath = rc.getLocationpath(); System.out.println("保存文件到目录" + fileInfo); DataOutputStream fileOut = new DataOutputStream( new BufferedOutputStream(new FileOutputStream(filePath))); receiveDs = new DatagramSocket(receivePort); System.out.println("我是文件接收器1,我已经运行"); int times = fileLen / dataLen;// 循环接收的次数 int restSize = fileLen % dataLen;// 接收剩下的字节 for (int i = 0; i < times; i++) { System.out.println("服务器已启动"); receiveDp = new DatagramPacket(inBuff, inBuff.length); receiveDs.receive(receiveDp); fileOut.write(inBuff, 0, receiveDp.getLength()); fileOut.flush(); } // 接收最后剩下,在inBuffer中能存下。 if (restSize != 0) { System.out.println("我有剩余"); receiveDp = new DatagramPacket(inBuff, inBuff.length); receiveDs.receive(receiveDp); fileOut.write(inBuff, 0, receiveDp.getLength()); fileOut.flush(); fileOut.close(); } System.out.println("接收完毕" + fileLen); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); if (receiveDs != null) { // 关闭receiveDs的对象 receiveDs.close(); } JOptionPane.showMessageDialog(null, "发送信息异常,请确认10000(接收端)号端口空闲,且网络连接正常", "网络异常", JOptionPane.ERROR_MESSAGE); System.exit(1); } } } class ReceiveConfirm implements ActionListener { // dingyi JLabel jl; JButton jb1, jb2; JPanel jp1, jp2; String headInfo = null; String myUserId = null; int fileLen = 0; float result = 0f; JFrame jf = null; private static String locationpath = "wait"; public ReceiveConfirm(String myUserId, String headInfo, int fileLen) { jf = new JFrame(); this.headInfo = headInfo; this.myUserId = myUserId; this.fileLen = fileLen; result = fileLen / 1024; System.out.println(myUserId + headInfo); // 创建 jl = new JLabel(myUserId + " 发来文件:【 " + headInfo + " 】,文件大小" + result + "KB,是否接受"); jb1 = new JButton("是"); jb1.addActionListener(this); jb2 = new JButton("否"); jb2.addActionListener(this); jp1 = new JPanel(); jp2 = new JPanel(); // 布局管理设置 // 添加组件 jp1.add(jl); jp2.add(jb1); jp2.add(jb2); jf.add(jp1, "Center"); jf.add(jp2, "South"); // 设置属性 jf.setSize(500, 120); jf.setTitle("提示信息"); jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jf.setVisible(true); jf.setLocation(550, 300); } @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub if (e.getSource() == jb1) { jf.dispose(); // FileDialogTest fdt=new FileDialogTest(); JFrame jf = new JFrame(); FileDialog fd = new FileDialog(jf, "选择保存文件路径", FileDialog.SAVE); fd.setVisible(true); System.out.println("保存位置" + fd.getDirectory() + fd.getFile()); String filePath = fd.getDirectory() + fd.getFile(); locationpath = filePath.replaceAll("\\\\", "/"); System.out.println("保存位置1" + locationpath); } } public String getLocationpath() { System.out.println("保存位置2" + locationpath); return locationpath; } }