zoukankan      html  css  js  c++  java
  • 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):



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

  • 相关阅读:
    gc buffer busy/gcs log flush sync与log file sync
    给Oracle年轻的初学者的几点建议
    Android 编程下帧动画在 Activity 启动时自动运行的几种方式
    Android 编程下 Touch 事件的分发和消费机制
    Java 编程下 static 关键字
    Java 编程下 final 关键字
    Android 编程下模拟 HOME 键效果
    Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?
    Extjs4 大型项目目录结构重构
    [转]SQLServer 2008 允许远程连接的配置方法
  • 原文地址:https://www.cnblogs.com/songtzu/p/2922288.html
Copyright © 2011-2022 走看看