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;
}
}