A complete example of file transfer based on Java Socket protocol, completed based on TCP communication.
In addition to TCP-based binary file transfer, some programming skills of JAVA Swing, demo program
The main functions are implemented as follows:
First, let’s take a look at the relationship between the entire Dome Class:
The following is a detailed explanation of the functions and code implementations of each class according to the above figure:
Server side:
The function of FileTransferServer class is first to create a server socket on port 9999 and
Start listening to the connection. The relevant codes are as follows:
private void startServer(int port) { try { serverSocket = new ServerSocket(port); System.out.println("Server started at port :" + port); while(true) { Socket client = serverSocket.accept(); // blocked & waiting for income socket System.out.println("Just connected to " + client.getRemoteSocketAddress()); FileReceiveTask task = new FileReceiveTask(client); bar.setValue(0); // reset it now task.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { bar.setValue((Integer) evt.getNewValue()); } } }); task.execute(); } } catch (IOException e) { e.printStackTrace(); } }About PropertyChangeListener, Java provides a very powerful tool class to monitor data changes in any Bean Model. The program implements the
SwingWorker's progress property value changes event capture, then update JProgressBar
Instance object, realizes refresh of UI. The complete source code of FileTransferServer class is as follows:
package com.gloomyfish.socket.tutorial.filetransfer; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; public class FileTransferServer extends JFrame implements ActionListener { /** * */ public final static String START_SVR = "Start"; public final static String SHUT_DOWN_SVR = "Shut Down"; public final static String END_FLAG = "EOF"; private static final long serialVersionUID = 1L; private ServerSocket serverSocket; private JButton startBtn; private JProgressBar bar; public FileTransferServer() { super("File Server"); initComponent(); setupListener(); } private void setupListener() { startBtn.addActionListener(this); } private void initComponent() { startBtn = new JButton(START_SVR); JPanel progressPanel = new JPanel(); progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS)); bar = new JProgressBar(); bar.setMinimum(0); bar.setMaximum(100); progressPanel.add(bar); getContentPane().setLayout(new BorderLayout()); JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); btnPanel.add(startBtn); getContentPane().add(btnPanel, BorderLayout.SOUTH); getContentPane().add(progressPanel, BorderLayout.CENTER); } private void startServer(int port) { try { serverSocket = new ServerSocket(port); System.out.println("Server started at port :" + port); while(true) { Socket client = serverSocket.accept(); // blocked & waiting for income socket System.out.println("Just connected to " + client.getRemoteSocketAddress()); FileReceiveTask task = new FileReceiveTask(client); bar.setValue(0); // reset it now task.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { bar.setValue((Integer) evt.getNewValue()); } } }); task.execute(); } } catch (IOException e) { e.printStackTrace(); } } public void showSuccess() { bar.setValue(100); JOptionPane.showMessageDialog(this, "file received successfully!"); } @Override public void actionPerformed(ActionEvent e) { if(START_SVR.equals(e.getActionCommand())) { Thread startThread = new Thread(new Runnable() { public void run() { startServer(9999); } }); startThread.start(); startBtn.setEnabled(false); } else if(SHUT_DOWN_SVR.equals(e.getActionCommand())) { } else { // do nothing... } } public static void main(String[] args) { FileTransferServer server = new FileTransferServer(); server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); server.setSize(400, 400); server.setResizable(false); server.setVisible(true); } } FileReceiveTask is a file acceptance class on the server side:
First, get the file name and file size from the established TCP stream, and then start accepting file content bytes
And write to the created file object stream, and finally verify whether the file size is equal to the written byte stream
Finally, send a message to the file sender to tell the other party that the file transfer is completed and the TCP stream can be closed.
The complete source code of this class is as follows:
package com.gloomyfish.socket.tutorial.filetransfer; import java.io.BufferedOutputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import javax.swing.SwingWorker; public class FileReceiveTask extends SwingWorker<Integer, Object> { private Socket _mSocket; public FileReceiveTask(Socket client) { this._mSocket = client; } @Override protected Integer doInBackground() throws Exception { // get file meta information DataInputStream input = new DataInputStream(_mSocket.getInputStream()); String fileName = input.readUTF(); int fileLength = (int)input.readLong(); // number of total bytes File file = new File("C://Users//fish//Downloads" + File.separator + fileName); BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file)); System.out.println("Received File Name = " + fileName); System.out.println("Received File size = " + fileLength/1024 + "KB"); // start to receive the content of the file and write them byte[] content = new byte[2048]; int offset = 0; int numReadBytes = 0; while(offset < fileLength && (numReadBytes = input.read(content)) > 0) { output.write(content, 0, numReadBytes); float precent = 100.0f * ((float)offset)/((float)fileLength); setProgress((int)precent); offset += numReadBytes; } System.out.println("numReadBytes = " + numReadBytes); if(offset < fileLength) { numReadBytes = input.read(content); System.out.println("numReadBytes = " + numReadBytes); System.out.println("File content error at server side"); } else { System.out.println("File Receive Task has done correctly"); } setProgress(100); // tell client to close the socket now, we already receive the file successfully!! BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(_mSocket.getOutputStream())); bufferedWriter.write("DONE/r/n"); bufferedWriter.flush(); // close the file and socket output.close(); _mSocket.close(); return 100; } } Client:
FileTransferClient is a client UI class that implements connection to the server and then selects
Files to be transferred (images, PDFs, Word documents, etc.). If not
Enter the server information and a prompt will pop up. The port has been specified as: 9999
The [send File] button will open the file selection box. After the user selects the file to be transferred, create the
FileTransferTask thread and start executing file transfer. The client UI code is as follows:
package com.gloomyfish.socket.tutorial.filetransfer; import java.awt.BorderLayout; import java.awt.FlowLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.net.InetSocketAddress; import java.net.SocketAddress; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JProgressBar; import javax.swing.JTextField; /** * I usually write English comments, and occasionally I also write Chinese comments, but I think that writing English* comments are more unified with the code, and nothing else. */ public class FileTransferClient extends JFrame implements ActionListener { /** * */ private static final long serialVersionUID = 1L; public final static String SEND_CMD = "Send File"; public final static int MINIMUM = 0; public final static int MAXIMUM = 100; // public final static String CONNECT_CMD = "Connect"; private JButton sendFileBtn; private JTextField serverField; private JTextField portField; private JProgressBar bar; public FileTransferClient() { super("File Transfer Client"); initComponents(); } private void initComponents() { getContentPane().setLayout(new BorderLayout()); JPanel progressPanel = new JPanel(); progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS); bar = new JProgressBar(); progressPanel.add(bar); bar.setMinimum(MINIMUM); bar.setMaximum(MAXIMUM); JPanel serverSettingPanel = new JPanel(); serverSettingPanel.setLayout(new GridLayout(2,2,5,5)); serverSettingPanel.setBorder(BorderFactory.createTitledBorder("Server Setting")); serverField = new JTextField(); portField = new JTextField(); serverSettingPanel.add(new JLabel("Server IP/Host:")); serverSettingPanel.add(serverField); serverSettingPanel.add(new JLabel("Server Port:")); serverSettingPanel.add(portField); sendFileBtn = new JButton(SEND_CMD); JPanel btnPanel = new JPanel(); btnPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); btnPanel.add(sendFileBtn); getContentPane().add(serverSettingPanel, BorderLayout.NORTH); getContentPane().add(btnPanel, BorderLayout.SOUTH); getContentPane().add(progressPanel, BorderLayout.CENTER); sendFileBtn.addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if(command.equals(SEND_CMD)) { if(checkNull()) { JOptionPane.showMessageDialog(this, "Please enter server host and port in order to set up the connection!"); return; } JFileChooser chooser = new JFileChooser(); int status = chooser.showOpenDialog(null); if (status == JFileChooser.APPROVE_OPTION) { File f = chooser.getSelectedFile(); SocketAddress address = new InetSocketAddress(getServer(), getPort()); FileTransferTask task = new FileTransferTask(f, address, this); bar.setValue(0); task.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { bar.setValue((Integer) evt.getNewValue()); } } }); task.execute(); // Asynchronous task execution} } else { // do nothing } } public void showSuccess() { bar.setValue(100); JOptionPane.showMessageDialog(this, "file send successfully!"); } public String getServer() { return serverField.getText().trim(); } public int getPort() { return Integer.parseInt(portField.getText().trim()); } /** * make sure the UI already have some correct input information here!!! * @return */ private boolean checkNull() { String serverName = serverField.getText(); String port = portField.getText(); if(serverName == null || serverName.length() == 0 || port == null || port.length() == 0) { return true; } try { Integer.parseInt(port); // try to parse it as server port number , validation code. } catch(NumberFormatException ne) { ne.printStackTrace(); return true; } return false; } public static void main(String[] args) { FileTransferClient client = new FileTransferClient(); client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); client.setSize(400, 400); client.setResizable(false); // client.pack(); client.setVisible(true); } } The main functions implemented by FileTransferTask are:
The complete source code of this class is as follows:
package com.gloomyfish.socket.tutorial.filetransfer; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; import java.net.SocketAddress; import javax.swing.SwingWorker; public class FileTransferTask extends SwingWorker<Integer, Object> { private File selectedFile; private Socket mSocket; private SocketAddress address; private FileTransferClient parent; public FileTransferTask(File file, SocketAddress address, FileTransferClient owner /*, JProgressBar progress*/) { this.address = address; this.selectedFile = file; mSocket = new Socket(); this.parent = owner; } @Override protected Integer doInBackground() throws Exception { // Get the size of the file long length = selectedFile.length(); if (length > Integer.MAX_VALUE) { throw new IOException("Could not completely read file " + selectedFile.getName() + " as it is too long (" + length + " bytes, max supported " + Integer.MAX_VALUE + ")"); } mSocket.connect(address); // Create the byte array to hold the file data mSocket.setSoLinger(true, 60); DataOutputStream dout = new DataOutputStream(mSocket.getOutputStream()); // now we start to send the file meta info. dout.writeUTF(selectedFile.getName()); dout.writeLong(length); dout.flush(); // end comment FileDataPackage pData = new FileDataPackage(); DataInputStream is = new DataInputStream(new FileInputStream(selectedFile)); byte[] bytes = new byte[2048]; // Read in the bytes int offset = 0; int numRead = 0; int fsize = (int)length; while (offset < fsize && (numRead=is.read(bytes, 0, bytes.length)) >= 0) { pData.setData(bytes, numRead); dout.write(pData.getPackageData(), 0, pData.getPackageData().length); dout.flush(); offset += numRead; float precent = 100.0f * ((float)offset)/((float)fsize); setProgress((int)precent); } System.out.println("total send bytes = " + offset); // Ensure all the bytes have been read in if (offset < fsize) { throw new IOException("Could not completely transfer file " + selectedFile.getName()); } mSocket.shutdownOutput(); // receive the file transfer successfully message from connection BufferedInputStream streamReader = new BufferedInputStream(mSocket.getInputStream()); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(streamReader)); String doneMsg = bufferedReader.readLine(); if("DONE".equals(doneMsg)) { parent.showSuccess(); } // Close the file input stream setProgress(100); // dout.close(); mSocket.close(); is.close(); System.out.println("close it now..."); return 100; } }The packet class is as follows, not explained!
package com.gloomyfish.socket.tutorial.filetransfer; /** * this is very simple file transfer protocol over TCP socket */ public class FileDataPackage { private int dataLength; // The length of data in the packet, two bytes private byte[] databuff; // The maximum data in the packet, the maximum number of meici does not exceed 2048 bytes public final static byte[] EOF = new byte[]{'E', 'O','F'}; public FileDataPackage() { dataLength = 0; databuff = new byte[2048]; } public byte[] getPackageData() { byte[] pData = new byte[dataLength]; // end comment System.arraycopy(databuff, 0, pData, 0, dataLength); return pData; } public void setData(byte[] data, int bsize) { dataLength = bsize; for(int i=0; i<databuff.length; i++) { if(i<bsize) { databuff[i] = data[i]; } else { databuff[i] = ' '; } } } }The maximum number of bytes sent per time is 2048 bytes. The final running effect of the program is as follows (win7 + JDK6u30):
The above is all about this article, I hope it will be helpful to everyone's learning.