这是我的第一个任务,编写一个应用Java socket进行文件传输的小程序。
根据要求,我编成了一个FTP,还是很不完善,比如跨网络传输时丢包情况相当严重。
这是服务器程序:
import javax.swing.filechooser.FileFilter;
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class RemoteFileServer extends JFrame {
private int listenPort = 3000, file_port = 3001;
private JButton path_bt, start_bt, stop_bt;
private JTextField path_field, port_field;
private JLabel path_label, port_label, label;
private boolean flag = true; //标记服务是否启动
private ServerSocket server, file_server;
private Socket incomingConnection = null, file_conn;
public RemoteFileServer() {
JFrame frame = new JFrame();
JPanel panel = new JPanel(); //主要是用它的流布局
frame.setSize(290, 140);
path_bt = new JButton("选择文件夹"); //选择作为根路径的文件夹,即此文件夹内的文件,能够在客户端列出。
label = new JLabel("服务已停止");
path_label = new JLabel("路径");
port_label = new JLabel("端口");
path_field = new JTextField(20);
path_field.setEditable(false);
port_field = new JTextField(20);
start_bt = new JButton("启动服务");
stop_bt = new JButton("停止服务");
//给按钮添加事件,选择客户端可下载的文件所在的文件夹
path_bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int value = chooser.showOpenDialog(null);
if (value == JFileChooser.APPROVE_OPTION) {
path_field.setText(chooser.getSelectedFile().getPath());
}
}
});
//启动服务
start_bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
flag = true;
if (!port_field.getText().trim().equals("")) {
listenPort = Integer.parseInt(port_field.getText().trim());
}
//启动服务的核心代码
acceptConnections(listenPort);
//提示,服务启动了
label.setText("服务已启动");
}
});
//停止服务
stop_bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
flag = false;
label.setText("服务已停止");
}
});
panel.add(path_label);
panel.add(path_field);
panel.add(port_label);
panel.add(port_field);
panel.add(path_bt);
panel.add(start_bt);
panel.add(stop_bt);
panel.add(label);
frame.add(panel);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private class ConnThread extends Thread {
public void run() {
while (flag) {
try {
incomingConnection = server.accept();
putFileList(incomingConnection);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private class FileThread extends Thread {
public void run() {
while (flag) {
try {
file_conn = file_server.accept();
//这里又启动一个线程,等待客户端获取文件
new SendThread().start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//线程类,等待客户机下载文件
private class SendThread extends Thread {
public void run() {
handleConnection(file_conn);
}
}
public void acceptConnections(int port) {
//创建ServerSocket
try {
if (server == null) {
server = new ServerSocket(port);
}
if (file_server == null) {
file_server = new ServerSocket(file_port);
}
//启动了一个线程,来等待客户端的链接,这样主程序才不会阻塞
new ConnThread().start();
new FileThread().start();
} catch (IOException e) {
e.printStackTrace();
}
}
//这是把文件夹里的文件列表传给客户端
//方法是,将所有的文件名组成一个字符串,之间以分号隔开,到客户端去解析
private void putFileList(Socket incomingConnection) {
//获得客户端流,将文件写到这个流里面去
OutputStream outputToSocket = null;
try {
outputToSocket = incomingConnection.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
DataOutputStream out = new DataOutputStream(outputToSocket);
File file = new File(path_field.getText());
String[] file_names = file.list();
String s = "";
for (String str : file_names) {
s = s + str + ";";
}
try {
out.writeUTF(s);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
//这是传送文件的核心代码,如果接受到客户端的消息以"#"a开头,那么解析出"#"后的文件名,并创建流给与下载
public void handleConnection(Socket conn) {
try {
//获得客户端流,将文件写到这个流里面去
OutputStream outputToSocket = conn.getOutputStream();
//获得客户端的输入流
InputStream client_input = conn.getInputStream();
//封装客户流
DataInputStream cleint_reader = new DataInputStream(client_input);
String str = cleint_reader.readUTF().trim();
System.out.println(str);
if (str.startsWith("#")) {
String file_str = str.substring(1, str.length());
System.out.println(file_str);
File file = new File(path_field.getText(), file_str);
FileInputStream filein = new FileInputStream(file);
byte[] b = new byte[1024];
int i = 0;
while (filein.read(b) != -1) {
outputToSocket.write(b);
}
outputToSocket.flush();
outputToSocket.close();
cleint_reader.close();
filein.close();
System.out.println("传输完毕");
}
} catch (Exception e) {
System.out.println("Error handling a client: " + e);
}
}
public static void main(String[] args) {
RemoteFileServer server = new RemoteFileServer();
}
}
*************************************分隔符**********************************
下面是客户端,本机调试IP:127.0.0.1,Port:3000
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.DefaultTableModel;
import java.io.*;
import java.net.*;
import java.util.Vector;
public class RemoteFileClient extends JFrame {
private JTextField tfip, tfport;
private String hostIP;
private JLabel tfip_label,port_label;
private int hostPort, filePort = 3001;
private Socket client;
private JButton connect_bt;
private String selected;
public RemoteFileClient(String aHostIp, int aHostPort) {
hostIP = aHostIp;
hostPort = aHostPort;
}
public RemoteFileClient() {
super("客户端");
setSize(350, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JFrame frame = new JFrame();
tfip_label = new JLabel("IP");
port_label = new JLabel("端口");
tfip = new JTextField(20);
tfport = new JTextField(20);
connect_bt = new JButton("连接");
// 连接添加事件,读取服务器的文件列表
connect_bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String ip = tfip.getText();// 取得IP
int port = Integer.parseInt(tfport.getText());
initClient(ip, port);
setUpConnect();// 连接到服务器端
}
});
panel.add(tfip_label);
panel.add(tfip);
panel.add(port_label);
panel.add(tfport);
panel.add(connect_bt);
frame.add(panel);
frame.setResizable(false);
frame.setSize(270,120);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void initClient(String aHostIp, int aHostPort) {
hostIP = aHostIp;
hostPort = aHostPort;
}
public void setUpConnect() {
try {
client = new Socket(hostIP, hostPort);
// 创建客户端的Socket,连接到Server上
DataInputStream in = new DataInputStream(client.getInputStream());
// 从socket获得流
String files = "";
files = in.readUTF();
// 取得从服务器取得的文件列表字符串
if (!files.trim().equals("")) {
showFileList(files);
}
in.close();
} catch (UnknownHostException e) {
System.out.println("Error setting up connection:unknow host at"
+ hostIP + ":" + hostPort);
} catch (IOException e) {
System.out.println("Error setting up socket connection:" + e);
}
}
// 创建一个文件列表窗口
private void showFileList(String files) {
JFrame frame = new JFrame();
frame.setSize(400, 400);
JTable table = new JTable();
createTable(table, files);
JScrollPane pane = new JScrollPane(table);
frame.add(pane);
JButton get_file = new JButton("传输文件");
// 获取文件
get_file.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new DownFile().start();// 启动一个下载线程,以免阻塞主线程
}
});
frame.add(get_file, BorderLayout.SOUTH);
frame.setVisible(true);
}
public class DownFile extends Thread {
public void run() {
JFileChooser chooser = new JFileChooser();
chooser.setSelectedFile(new File(".", selected));
// 设置默认保存的文件名
int value = chooser.showSaveDialog(null);
if (value == JFileChooser.APPROVE_OPTION) {
try {
client = new Socket(hostIP, filePort);
// 这里首先给服务器一个消息,消息以"#"开头加上文件名,以告诉服务器下载的文件是什么
DataOutputStream out = new DataOutputStream(client
.getOutputStream());
out.writeUTF("#" + selected);
out.flush();
// 取得选取的文件
File file = chooser.getSelectedFile();
// 准备写入
FileOutputStream fileout = new FileOutputStream(file);
// 取得服务器的流
InputStream in = client.getInputStream();
// 传输过程
byte[] b = new byte[1024];
int i = 0;
while (in.read(b) != -1) {
fileout.write(b);
}
fileout.flush();
// 关闭流
fileout.close();
out.close();
in.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
// 创建文件列表的,参考Table的API
private void createTable(JTable table, String files) {
DefaultTableModel tableModel = new DefaultTableModel();
final Vector row = new Vector();
Vector cell;
String[] f = files.split(";");
for (String str : f) {
cell = new Vector();
cell.add(str);
row.add(cell);
}
Vector head = new Vector();
head.add("文件");
tableModel.setDataVector(row, head);
table.setModel(tableModel);
ListSelectionModel model = table.getSelectionModel();
model.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
int index = ((DefaultListSelectionModel) (e.getSource()))
.getAnchorSelectionIndex();
selected = (String) ((Vector) row.get(index)).get(0);
System.out.println(selected);
}
}
});
}
public static void main(String[] argumnets) {
RemoteFileClient frame = new RemoteFileClient();
}
}