• Java Socket编程 基于TCP方式的二进制文件传输【转】http://blog.csdn.net/jia20003/article/details/8248221


    此人博客挺好的,推荐一个!

    一个基于Java Socket协议之上文件传输的完整示例,基于TCP通信完成。

    除了基于TCP的二进制文件传输,还演示了JAVA Swing的一些编程技巧,Demo程序

    实现主要功能有以下几点:

    1.      基于Java Socket的二进制文件传输(包括图片,二进制文件,各种文档work,

             PDF)

    2.      SwingWorker集合JProgressBar显示实时传输/接受完成的百分比

    3.      其它一些Swing多线程编程技巧

    首先来看一下整个Dome的Class之间的关系图:


    下面按照上图来详细解释各个类的功能与代码实现:

    服务器端:

    FileTransferServer类的功能首先是在端口9999创建一个服务器套接字并

    开始监听连接。相关代码如下:

    1. private void startServer(int port) {  
    2.     try {  
    3.         serverSocket = new ServerSocket(port);  
    4.         System.out.println("Server started at port :" + port);  
    5.         while(true) {  
    6.             Socket client = serverSocket.accept(); // blocked & waiting for income socket  
    7.             System.out.println("Just connected to " + client.getRemoteSocketAddress());  
    8.             FileReceiveTask task = new FileReceiveTask(client);  
    9.             bar.setValue(0); // reset it now  
    10.             task.addPropertyChangeListener(new PropertyChangeListener() {  
    11.                 public void propertyChange(PropertyChangeEvent evt) {  
    12.                     if ("progress".equals(evt.getPropertyName())) {  
    13.                         bar.setValue((Integer) evt.getNewValue());  
    14.                     }  
    15.                 }  
    16.             });  
    17.               
    18.             task.execute();  
    19.         }  
    20.   
    21.     } catch (IOException e) {  
    22.         e.printStackTrace();  
    23.     }  
    24. }  

    关于PropertyChangeListener, Java提供了一个非常有力的工具类来

    监控任意Bean Model的数据改变,程序通过添加该监听器实现对

    SwingWorker的progress属性值改变的事件捕获,然后更新JProgressBar

    实例对象,实现了UI的刷新。FileTransferServer类的完整源代码如下:

    1. package com.gloomyfish.socket.tutorial.filetransfer;  
    2.   
    3. import java.awt.BorderLayout;  
    4. import java.awt.FlowLayout;  
    5. import java.awt.event.ActionEvent;  
    6. import java.awt.event.ActionListener;  
    7. import java.beans.PropertyChangeEvent;  
    8. import java.beans.PropertyChangeListener;  
    9. import java.io.IOException;  
    10. import java.net.ServerSocket;  
    11. import java.net.Socket;  
    12.   
    13. import javax.swing.BoxLayout;  
    14. import javax.swing.JButton;  
    15. import javax.swing.JFrame;  
    16. import javax.swing.JOptionPane;  
    17. import javax.swing.JPanel;  
    18. import javax.swing.JProgressBar;  
    19.   
    20. public class FileTransferServer extends JFrame implements ActionListener {  
    21.     /** 
    22.      *  
    23.      */  
    24.     public final static String START_SVR = "Start";  
    25.     public final static String SHUT_DOWN_SVR = "Shut Down";  
    26.     public final static String END_FLAG = "EOF";  
    27.     private static final long serialVersionUID = 1L;  
    28.     private ServerSocket serverSocket;  
    29.     private JButton startBtn;  
    30.     private JProgressBar bar;  
    31.     public FileTransferServer() {  
    32.         super("File Server");  
    33.         initComponent();  
    34.         setupListener();  
    35.     }  
    36.   
    37.     private void setupListener() {  
    38.         startBtn.addActionListener(this);  
    39.     }  
    40.   
    41.     private void initComponent() {  
    42.         startBtn = new JButton(START_SVR);  
    43.         JPanel progressPanel = new JPanel();  
    44.         progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS));  
    45.         bar = new JProgressBar();  
    46.         bar.setMinimum(0);  
    47.         bar.setMaximum(100);  
    48.         progressPanel.add(bar);  
    49.         getContentPane().setLayout(new BorderLayout());  
    50.         JPanel btnPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));  
    51.         btnPanel.add(startBtn);  
    52.         getContentPane().add(btnPanel, BorderLayout.SOUTH);  
    53.         getContentPane().add(progressPanel, BorderLayout.CENTER);  
    54.     }  
    55.       
    56.     private void startServer(int port) {  
    57.         try {  
    58.             serverSocket = new ServerSocket(port);  
    59.             System.out.println("Server started at port :" + port);  
    60.             while(true) {  
    61.                 Socket client = serverSocket.accept(); // blocked & waiting for income socket  
    62.                 System.out.println("Just connected to " + client.getRemoteSocketAddress());  
    63.                 FileReceiveTask task = new FileReceiveTask(client);  
    64.                 bar.setValue(0); // reset it now  
    65.                 task.addPropertyChangeListener(new PropertyChangeListener() {  
    66.                     public void propertyChange(PropertyChangeEvent evt) {  
    67.                         if ("progress".equals(evt.getPropertyName())) {  
    68.                             bar.setValue((Integer) evt.getNewValue());  
    69.                         }  
    70.                     }  
    71.                 });  
    72.                   
    73.                 task.execute();  
    74.             }  
    75.   
    76.         } catch (IOException e) {  
    77.             e.printStackTrace();  
    78.         }  
    79.     }  
    80.       
    81.     public void showSuccess() {  
    82.         bar.setValue(100);  
    83.         JOptionPane.showMessageDialog(this"file received successfully!");  
    84.     }  
    85.   
    86.     @Override  
    87.     public void actionPerformed(ActionEvent e) {  
    88.         if(START_SVR.equals(e.getActionCommand())) {  
    89.             Thread startThread = new Thread(new Runnable() {  
    90.                 public void run() {  
    91.                     startServer(9999);  
    92.                 }  
    93.             });  
    94.             startThread.start();  
    95.             startBtn.setEnabled(false);  
    96.         } else if(SHUT_DOWN_SVR.equals(e.getActionCommand())) {  
    97.   
    98.         } else {  
    99.             // do nothing...  
    100.         }  
    101.     }  
    102.       
    103.     public static void main(String[] args) {  
    104.         FileTransferServer server = new FileTransferServer();  
    105.         server.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    106.         server.setSize(400400);  
    107.         server.setResizable(false);  
    108.         server.setVisible(true);  
    109.     }  
    110. }  

    FileReceiveTask是服务器端的文件接受类:

    首先从建立的TCP流中得到文件名与文件大小,然后开始接受文件内容字节

    并写入创建的文件对象流中,最后验证文件大小与写入的字节流是否相等

    最后发送一条消息到文件发送方,告诉对方文件传输完成,可以关闭TCP流。

    该类的完整源代码如下:

    1. package com.gloomyfish.socket.tutorial.filetransfer;  
    2.   
    3. import java.io.BufferedOutputStream;  
    4. import java.io.BufferedWriter;  
    5. import java.io.DataInputStream;  
    6. import java.io.File;  
    7. import java.io.FileOutputStream;  
    8. import java.io.OutputStreamWriter;  
    9. import java.net.Socket;  
    10.   
    11. import javax.swing.SwingWorker;  
    12.   
    13. public class FileReceiveTask extends SwingWorker<Integer, Object> {  
    14.     private Socket _mSocket;  
    15.     public FileReceiveTask(Socket client) {  
    16.         this._mSocket = client;  
    17.     }  
    18.   
    19.     @Override  
    20.     protected Integer doInBackground() throws Exception {  
    21.         // get file meta information  
    22.         DataInputStream input = new DataInputStream(_mSocket.getInputStream());  
    23.         String fileName = input.readUTF();  
    24.         int fileLength = (int)input.readLong(); // number of total bytes  
    25.         File file = new File("C:\\Users\\fish\\Downloads" + File.separator + fileName);  
    26.         BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(file));  
    27.         System.out.println("Received File Name = " + fileName);  
    28.         System.out.println("Received File size = " + fileLength/1024 + "KB");  
    29.           
    30.         // start to receive the content of the file and write them  
    31.         byte[] content = new byte[2048];  
    32.         int offset = 0;  
    33.         int numReadBytes = 0;  
    34.         while(offset < fileLength && (numReadBytes = input.read(content)) > 0) {  
    35.             output.write(content, 0, numReadBytes);  
    36.             float precent = 100.0f * ((float)offset)/((float)fileLength);  
    37.             setProgress((int)precent);  
    38.             offset += numReadBytes;  
    39.         }  
    40.         System.out.println("numReadBytes = " + numReadBytes);  
    41.         if(offset < fileLength) {  
    42.             numReadBytes = input.read(content);  
    43.             System.out.println("numReadBytes = " + numReadBytes);  
    44.             System.out.println("File content error at server side");  
    45.         } else {  
    46.             System.out.println("File Receive Task has done correctly");  
    47.         }  
    48.         setProgress(100);  
    49.           
    50.         // tell client to close the socket now, we already receive the file successfully!!  
    51.         BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(_mSocket.getOutputStream()));  
    52.         bufferedWriter.write("DONE\r\n");  
    53.         bufferedWriter.flush();  
    54.           
    55.         // close the file and socket  
    56.         output.close();  
    57.         _mSocket.close();  
    58.         return 100;  
    59.     }  
    60.   
    61. }  

    客户端:

    FileTransferClient是客户端UI类,用来实现到服务端的连接,然后选择

    要传输的文件(图片,PDF,Word文档等各种二进制文件)。如果没有

    输入服务器信息,会弹出提示要求输入。端口已经指定为:9999

    【send File】按钮会打开文件选择框,用户选择要传输文件以后,创建

    FileTransferTask线程,并开始执行文件传送。客户端UI代码如下:

    1. package com.gloomyfish.socket.tutorial.filetransfer;  
    2.   
    3. import java.awt.BorderLayout;  
    4. import java.awt.FlowLayout;  
    5. import java.awt.GridLayout;  
    6. import java.awt.event.ActionEvent;  
    7. import java.awt.event.ActionListener;  
    8. import java.beans.PropertyChangeEvent;  
    9. import java.beans.PropertyChangeListener;  
    10. import java.io.File;  
    11. import java.net.InetSocketAddress;  
    12. import java.net.SocketAddress;  
    13.   
    14. import javax.swing.BorderFactory;  
    15. import javax.swing.BoxLayout;  
    16. import javax.swing.JButton;  
    17. import javax.swing.JFileChooser;  
    18. import javax.swing.JFrame;  
    19. import javax.swing.JLabel;  
    20. import javax.swing.JOptionPane;  
    21. import javax.swing.JPanel;  
    22. import javax.swing.JProgressBar;  
    23. import javax.swing.JTextField;  
    24. /** 
    25.  * 我一般写英文注释,偶尔我也会写中文注释,只是觉得写英文 
    26.  * 注释跟代码比较统一,无他。 
    27.  *  
    28.  * @Date 2012-11-30 
    29.  * @author fish 
    30.  * 
    31.  */  
    32. public class FileTransferClient extends JFrame implements ActionListener {  
    33.     /** 
    34.      *  
    35.      */  
    36.     private static final long serialVersionUID = 1L;  
    37.     public final static String SEND_CMD = "Send File";  
    38.     public final static int MINIMUM = 0;  
    39.     public final static int MAXIMUM = 100;  
    40.     // public final static String CONNECT_CMD = "Connect";  
    41.     private JButton sendFileBtn;  
    42.     private JTextField serverField;  
    43.     private JTextField portField;  
    44.     private JProgressBar bar;  
    45.       
    46.     public FileTransferClient() {  
    47.         super("File Transfer Client");  
    48.         initComponents();  
    49.     }  
    50.   
    51.     private void initComponents() {  
    52.         getContentPane().setLayout(new BorderLayout());  
    53.         JPanel progressPanel = new JPanel();  
    54.         progressPanel.setLayout(new BoxLayout(progressPanel, BoxLayout.Y_AXIS));  
    55.         bar = new JProgressBar();  
    56.         progressPanel.add(bar);  
    57.         bar.setMinimum(MINIMUM);  
    58.         bar.setMaximum(MAXIMUM);  
    59.         JPanel serverSettingPanel = new JPanel();  
    60.         serverSettingPanel.setLayout(new GridLayout(2,2,5,5));  
    61.         serverSettingPanel.setBorder(BorderFactory.createTitledBorder("Server Setting"));  
    62.         serverField = new JTextField();  
    63.         portField = new JTextField();  
    64.         serverSettingPanel.add(new JLabel("Server IP/Host:"));  
    65.         serverSettingPanel.add(serverField);  
    66.         serverSettingPanel.add(new JLabel("Server Port:"));  
    67.         serverSettingPanel.add(portField);  
    68.           
    69.         sendFileBtn = new JButton(SEND_CMD);  
    70.         JPanel btnPanel = new JPanel();  
    71.         btnPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));  
    72.         btnPanel.add(sendFileBtn);  
    73.         getContentPane().add(serverSettingPanel, BorderLayout.NORTH);  
    74.         getContentPane().add(btnPanel, BorderLayout.SOUTH);  
    75.         getContentPane().add(progressPanel, BorderLayout.CENTER);  
    76.         sendFileBtn.addActionListener(this);  
    77.     }  
    78.   
    79.     @Override  
    80.     public void actionPerformed(ActionEvent e) {  
    81.         String command = e.getActionCommand();  
    82.         if(command.equals(SEND_CMD)) {  
    83.             if(checkNull()) {  
    84.                 JOptionPane.showMessageDialog(this"Please enter server host and port in order to set up the connection!");  
    85.                 return;  
    86.             }  
    87.             JFileChooser chooser = new JFileChooser();  
    88.             int status = chooser.showOpenDialog(null);  
    89.             if (status == JFileChooser.APPROVE_OPTION) {  
    90.                 File f = chooser.getSelectedFile();  
    91.                 SocketAddress address = new InetSocketAddress(getServer(), getPort());  
    92.                 FileTransferTask task = new FileTransferTask(f, address, this);  
    93.                 bar.setValue(0);  
    94.                 task.addPropertyChangeListener(new PropertyChangeListener() {  
    95.                     public void propertyChange(PropertyChangeEvent evt) {  
    96.                         if ("progress".equals(evt.getPropertyName())) {  
    97.                             bar.setValue((Integer) evt.getNewValue());  
    98.                         }  
    99.                     }  
    100.                 });  
    101.                 task.execute(); // 异步task执行  
    102.             }  
    103.         } else {  
    104.             // do nothing  
    105.         }  
    106.     }  
    107.       
    108.     public void showSuccess() {  
    109.         bar.setValue(100);  
    110.         JOptionPane.showMessageDialog(this"file send successfully!");  
    111.     }  
    112.       
    113.     public String getServer() {  
    114.         return serverField.getText().trim();  
    115.     }  
    116.       
    117.     public int getPort() {  
    118.         return Integer.parseInt(portField.getText().trim());  
    119.     }  
    120.     /** 
    121.      * make sure the UI already have some correct input information here!!! 
    122.      * @return 
    123.      */  
    124.     private boolean checkNull() {  
    125.         String serverName = serverField.getText();  
    126.         String port = portField.getText();  
    127.         if(serverName == null || serverName.length() == 0 || port == null || port.length() == 0) {  
    128.             return true;  
    129.         }  
    130.           
    131.         try {  
    132.             Integer.parseInt(port); // try to parse it as server port number , validation code.  
    133.         } catch(NumberFormatException ne) {  
    134.             ne.printStackTrace();  
    135.             return true;  
    136.         }  
    137.         return false;  
    138.     }  
    139.       
    140.     public static void main(String[] args) {  
    141.         FileTransferClient client = new FileTransferClient();  
    142.         client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    143.         client.setSize(400400);  
    144.         client.setResizable(false);  
    145.         // client.pack();  
    146.         client.setVisible(true);  
    147.     }  
    148.   
    149. }  

    FileTransferTask实现的功能主要有:

    1. 发送文件meta信息到接受方(文件名与文件大小)

    2. 读取文件内容字节写入Socket字节流中,发送到接受方

    3. 从Socket字节流中读取对方接受完成通知信息,调用弹出文件传输成功信息

    该类完全源代码如下:

    1. package com.gloomyfish.socket.tutorial.filetransfer;  
    2.   
    3. import java.io.BufferedInputStream;  
    4. import java.io.BufferedReader;  
    5. import java.io.DataInputStream;  
    6. import java.io.DataOutputStream;  
    7. import java.io.File;  
    8. import java.io.FileInputStream;  
    9. import java.io.IOException;  
    10. import java.io.InputStreamReader;  
    11. import java.net.Socket;  
    12. import java.net.SocketAddress;  
    13.   
    14. import javax.swing.SwingWorker;  
    15.   
    16. public class FileTransferTask extends SwingWorker<Integer, Object> {  
    17.     private File selectedFile;  
    18.     private Socket mSocket;  
    19.     private SocketAddress address;  
    20.     private FileTransferClient parent;  
    21.       
    22.     public FileTransferTask(File file, SocketAddress address, FileTransferClient owner /*, JProgressBar progress*/) {  
    23.         this.address = address;  
    24.         this.selectedFile = file;  
    25.         mSocket = new Socket();  
    26.         this.parent = owner;  
    27.     }  
    28.       
    29.     @Override  
    30.     protected Integer doInBackground() throws Exception {  
    31.         // Get the size of the file  
    32.         long length = selectedFile.length();  
    33.         if (length > Integer.MAX_VALUE) {  
    34.             throw new IOException("Could not completely read file " + selectedFile.getName() + " as it is too long (" + length + " bytes, max supported " + Integer.MAX_VALUE + ")");  
    35.         }  
    36.           
    37.         mSocket.connect(address);  
    38.           
    39.         // Create the byte array to hold the file data  
    40.         mSocket.setSoLinger(true60);  
    41.         DataOutputStream dout = new DataOutputStream(mSocket.getOutputStream());  
    42.         // now we start to send the file meta info.  
    43.         dout.writeUTF(selectedFile.getName());  
    44.         dout.writeLong(length);  
    45.         dout.flush();  
    46.         // end comment  
    47.         FileDataPackage pData = new FileDataPackage();  
    48.         DataInputStream is = new DataInputStream(new FileInputStream(selectedFile));  
    49.         byte[] bytes = new byte[2048];  
    50.   
    51.         // Read in the bytes  
    52.         int offset = 0;  
    53.         int numRead = 0;  
    54.         int fsize = (int)length;  
    55.         while (offset < fsize && (numRead=is.read(bytes, 0, bytes.length)) >= 0) {  
    56.             pData.setData(bytes, numRead);  
    57.             dout.write(pData.getPackageData(), 0, pData.getPackageData().length);  
    58.             dout.flush();  
    59.             offset += numRead;  
    60.             float precent = 100.0f * ((float)offset)/((float)fsize);  
    61.             setProgress((int)precent);  
    62.         }  
    63.         System.out.println("total send bytes = " + offset);  
    64.         // Ensure all the bytes have been read in  
    65.         if (offset < fsize) {  
    66.             throw new IOException("Could not completely transfer file " + selectedFile.getName());  
    67.         }  
    68.         mSocket.shutdownOutput();  
    69.           
    70.         // receive the file transfer successfully message from connection  
    71.           
    72.         BufferedInputStream streamReader = new BufferedInputStream(mSocket.getInputStream());  
    73.         BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(streamReader));  
    74.         String doneMsg = bufferedReader.readLine();  
    75.         if("DONE".equals(doneMsg)) {  
    76.             parent.showSuccess();  
    77.         }  
    78.         // Close the file input stream   
    79.         setProgress(100);  
    80.         // dout.close();  
    81.         mSocket.close();  
    82.         is.close();  
    83.         System.out.println("close it now......");  
    84.         return 100;  
    85.     }  
    86. }  

    数据包类如下,不解释!

    1. package com.gloomyfish.socket.tutorial.filetransfer;  
    2. /** 
    3.  * this is very simple file transfer protocol over TCP socket 
    4.  * @date 2012-12-01 
    5.  * @author zhigang jia 
    6.  * 
    7.  */  
    8. public class FileDataPackage {  
    9.   
    10.     private int dataLength; // 数据包中数据长度,两个字节  
    11.     private byte[] databuff; // 数据包中数据,meici最大不超过2048字节  
    12.       
    13.     public final static byte[] EOF = new byte[]{'E''O','F'};  
    14.       
    15.     public FileDataPackage() {  
    16.         dataLength = 0;  
    17.         databuff = new byte[2048];  
    18.     }  
    19.       
    20.     public byte[] getPackageData() {  
    21.         byte[] pData = new byte[dataLength];  
    22.         // end comment  
    23.         System.arraycopy(databuff, 0, pData, 0, dataLength);  
    24.         return pData;  
    25.     }  
    26.       
    27.     public void setData(byte[] data, int bsize) {  
    28.         dataLength = bsize;  
    29.         for(int i=0; i<databuff.length; i++) {  
    30.             if(i<bsize) {  
    31.                 databuff[i] = data[i];  
    32.             } else {  
    33.                 databuff[i] = ' ';  
    34.             }  
    35.         }  
    36.     }  
    37. }  

    每次发送的最大字节数为2048个字节。程序最终运行效果如下(win7 + JDK6u30):



    觉得不错,请顶一下啊,谢谢!

  • 相关阅读:
    TensorFlow优化器
    TensorFlow读取csv文件过程
    0126Go时间
    0125GoXML 转换
    0130Go数值解析
    0127Go时间戳
    0131GoURL 解析
    0128Go时间格式化
    0133GoBase64
    0124GoJSON 转换
  • 原文地址:https://www.cnblogs.com/songtzu/p/2922288.html
Copyright © 2020-2023  润新知