热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Java基于TCP方式的二进制文件传输

这篇文章主要为大家介绍了Java基于TCP方式的二进制文件传输,一个基于JavaSocket协议之上文件传输的完整示例,基于TCP通信完成,感兴趣的小伙伴们可以参考一下

一个基于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 { 
 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  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 

客户端:
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; 
/** 
 * 我一般写英文注释,偶尔我也会写中文注释,只是觉得写英文 
 * 注释跟代码比较统一,无他。 
 */ 
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 { 
 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 = 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 

数据包类如下,不解释!

package com.gloomyfish.socket.tutorial.filetransfer; 
/** 
 * this is very simple file transfer protocol over TCP socket 
 */ 
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

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

以上就是本文的全部内容,希望对大家的学习有所帮助。


推荐阅读
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了如何找到并终止在8080端口上运行的进程的方法,通过使用终端命令lsof -i :8080可以获取在该端口上运行的所有进程的输出,并使用kill命令终止指定进程的运行。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文详细介绍了云服务器API接口的概念和作用,以及如何使用API接口管理云上资源和开发应用程序。通过创建实例API、调整实例配置API、关闭实例API和退还实例API等功能,可以实现云服务器的创建、配置修改和销毁等操作。对于想要学习云服务器API接口的人来说,本文提供了详细的入门指南和使用方法。如果想进一步了解相关知识或阅读更多相关文章,请关注编程笔记行业资讯频道。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 如何基于ggplot2构建相关系数矩阵热图以及一个友情故事
    本文介绍了如何在rstudio中安装ggplot2,并使用ggplot2构建相关系数矩阵热图。同时,通过一个友情故事,讲述了真爱难觅的故事背后的数据量化和皮尔逊相关系数的概念。故事中的小伙伴们在本科时参加各种考试,其中有些沉迷网络游戏,有些热爱体育,通过他们的故事,展示了不同兴趣和特长对学习和成绩的影响。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
author-avatar
手机用户2502887197
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有