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

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

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

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

PDF)

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

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

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

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

服务器端:

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

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

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

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

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

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

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

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是服务器端的文件接受类:

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

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

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

该类的完整源代码如下:

package com.gloomyfish.socket.tutorial.filetransfer;  import java.io.BufferedOutputStream; import java.io.BufferedWriter; 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;     }  } 

客户端:

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

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

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

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

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

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; /**  * 我一般写英文注释,偶尔我也会写中文注释,只是觉得写英文  * 注释跟代码比较统一,无他。  *   * @Date 2012-11-30  * @author fish  *  */ 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(); // 异步task执行             }       } 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);    }  } 

FileTransferTask实现的功能主要有:

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

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

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

该类完全源代码如下:

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

数据包类如下,不解释!

package com.gloomyfish.socket.tutorial.filetransfer; /**  * this is very simple file transfer protocol over TCP socket  * @date 2012-12-01  * @author zhigang jia  *  */ public class FileDataPackage {     private int dataLength; // 数据包中数据长度,两个字节     private byte[] databuff; // 数据包中数据,meici最大不超过2048字节      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] = ' ';           }       }   } } 

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

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

转载务必注明

转载于:https://blog.51cto.com/gloomyfish/1400397

Java Socket编程 - 基于TCP方式的二进制文件传输相关推荐

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

    此人博客挺好的,推荐一个! 一个基于Java Socket协议之上文件传输的完整示例,基于TCP通信完成. 除了基于TCP的二进制文件传输,还演示了JAVA Swing的一些编程技巧,Demo程序 实 ...

  2. tcp java实例_实现了基于TCP的Java Socket编程实例代码

    实现了基于TCP的Java Socket编程,功能很简单:客户端向服务器端输出一名话"connect",服务器端接收输出到控制台并向客户端输出一名话"Hello" ...

  3. Java进阶:基于TCP的网络实时聊天室(socket通信案例)

    目录 开门见山 一.数据结构Map 二.保证线程安全 三.群聊核心方法 四.聊天室具体设计 0.用户登录服务器 1.查看当前上线用户 2.群聊 3.私信 4.退出当前聊天状态 5.离线 6.查看帮助 ...

  4. Linux下基于TCP的简易文件传输(socket编程)

    Linux下基于TCP的简易文件传输(socket编程) OSI和TCP/IP: 关于TCP/IP协议 关于TCP协议 TCP编程的一般步骤[^2] TCP文件传输实现 功能概述 服务器编程 客户端编 ...

  5. Java Socket编程----通信是这样炼成的

    转载自 Java Socket编程----通信是这样炼成的 Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socke ...

  6. Java Socket编程如何建立两者关系

    转自:http://developer.51cto.com/art/201003/190582.htm Java Socket编程需要大家详细的学习,有关的技术一直在不断的更新.那么要如何才能掌握好有 ...

  7. 网络编程——基于TCP协议的通讯录【课程设计】

    网络编程--基于TCP协议的通讯录[课程设计] 本文目录 网络编程--基于TCP协议的通讯录[课程设计] 一.设计题目和要求 设计目标: 课程设计系统组成及模块功能: 二.设计内容 服务端 客户端 S ...

  8. JAVA socket编程 Datagram套接字 UDP协议(转)

      查看文章     JAVA socket编程 Datagram套接字 UDP协议 2009-05-13 09:35 1 UDP套接字 数据报(Datagram)是网络层数据单元在介质上传输信息的一 ...

  9. Java Socket编程详解

    Java Socket编程是Java网络编程很重要的内容,现参考了许多资料,总结如下: 1. Java网络编程原理+Socket编程 http://www.cnblogs.com/linzheng/a ...

最新文章

  1. 开源分布式平台-mooon系统结构
  2. 3.1.9 OS之二级页表的原理和地址结构
  3. 呼和浩特 计算机编程入门先学什么,学好UG编程先学什么?应该先弄懂这些问题...
  4. html字符串使用xpath,使用XPath和regex在HTML注释中提取文本
  5. Web前端经典面试题-JavaScript
  6. vue 打包后本地先自己启动服务 anywhere 非常好用
  7. 可以学计算机再学美术,想学习板绘?教你如何在电脑学习绘画!
  8. 年度编程榜出炉!Python第一,Java程序员哭晕:又翻车了!
  9. thinkpadX1C2021充不进去电(去除静电后依旧无效的来看看)
  10. 路飞学城python开发ftp_路飞学城-Python开发集训-第1章
  11. GPU共享内存:pycuda使用教程
  12. 32位计算机64位计算机实质,4G内存电脑安装32位还是64位win7系统?实际详细性能测试!...
  13. oracle把一列拆成多列,Oracle将一列分成多列
  14. 微信小程序使用Socket
  15. jQuery项目:京东商品详情页
  16. 域名过户操作流程及常见问题
  17. vue实现上传图片和显示图片
  18. vscode中好用的git相关的插件
  19. 艾永亮:时代的较量,谁在定义四个轮子的未来?
  20. 1602液晶显示简易计算器

热门文章

  1. 使用Python中的reduce()函数求积
  2. 代码流程图怎么画_程序流图怎么画?详细图文解析绘制程序流程图
  3. 动画库NineOldAndroids
  4. 无线网卡服务端工具airserv-ng
  5. 一张图解释什么是遗传算法_一张图告诉你什么叫真正的满配m416,吃鸡玩家看懵了...
  6. oracle索引本地打钩,Oracle
  7. html region 折叠,js代码折叠的方法//#region 代码 //#endregion
  8. spark官方文档_Apache Spark 文档传送门
  9. python 优先队列_Python中heapq与优先队列【详细】
  10. python6翻_洗礼灵魂,修炼python(6)--活起来的代码+列表