`
ljy325
  • 浏览: 17911 次
  • 性别: Icon_minigender_1
  • 来自: 南宁
社区版块
存档分类
最新评论

java多线程网络传输文件(非同步)-2008-08-17

阅读更多
利用 Socket 套接字进行面向连接通信的编程。客户端读取本地文件并发送;服务器接收文件并保存到本地文件系统中。
使用说明:请将TransferClient, TransferServer, TempFile三个类编译,他们的类包是FileServer.
客户端:
修改TransferClient: serPort, serIP, filePath, blockNum,的值来符合您机器的系统环境;或者用命令行
格式: java FileServer.TransferClient 文件路径+文件名 服务器IP地址 端口 线程数
C:\>java FileServer.TransferClient e:\GREbulletin.pdf 192.168.1.105 2008 5
服务端:
修改TransferServer: serPort, tempFolder的值来符合您机器的系统环境;或者用命令行
格式: java FileServer.TransferServer 端口 文件夹路径
C:\>java FileServer.TransferServer 2008 F:\tempFolder


文件传输服务端---------------------------------------------------------
package FileServer;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

/**
 * Description Socket文件传输服务端
 * 默认支持多线程传输,未支持断点续传,未支持内网UDF传输
 * Creation Date 07-08-2008 9:00
 * @author 卢俊宇
 * @version 1.0
 */
public class TransferServer {
 
 /**
  * @param args[0] 端口默认2008(例: 2008)
  * @param args[1] 接收文件存放路径,默认:和FileServer同一目录\ServerReceive
  *       (例:x:\example\example\)
  */
 public static void main(String[] args) {
  try {
   int serPort = 2008;//服务器默认端口2008
   String tempFolder = System.getProperty("user.dir")+"\\ServerReceive";//临时文件夹,用于存放接收文件
   ServerSocket ss = null;//设定Socket
   if (args.length<1 || null==args) {
    ss = new ServerSocket(serPort);
   }else {
    //检测输入端口是否正确
    if (args[0].replaceAll("\\D", "")!="") {
     serPort = Integer.parseInt(args[0].replaceAll("\\D", ""));
    }else {
     System.out.println("输入的端口有错误,使用系统默认端口");
    }
    ss = new ServerSocket(serPort);
    if (args[1].length()>0) {
     tempFolder = args[1];
    }
   }
   System.out.println("Welcome to TransferServer");
   System.out.println("服务器启动,监听端口" + ss.getLocalPort());
   System.out.println("服务器临时文件路径: "+tempFolder);
   while (true) {
    Socket s = ss.accept();
    new Thread(new ServerThread(s,tempFolder)).start();
   }

  } catch (IOException e) {
   e.getMessage();
   System.out.println("服务器端口被占用,或其他问题.");
  }
 }

}

/**
 * Description 服务器线程
 * @author 卢俊宇
 * @param tempFolder 接收文件存放路径,默认:TransferServer.class所在目录\ServerReceive
 *       (例:x:\example\example\)
 * @version 1.1
 */
class ServerThread implements Runnable {

 Socket s;// 实例化socket类
 private String tempFolder;//临时文件夹名
 public ServerThread(Socket s,String tempFolder) {
  this.s = s;
  this.tempFolder = tempFolder;
 }

 @SuppressWarnings("deprecation")
 public void run() {
  try {

   InputStream ins = s.getInputStream();
   OutputStream outs = s.getOutputStream();

   DataInputStream dis = new DataInputStream(ins);
   DataOutputStream dos = new DataOutputStream(outs);

   // 取得线程ID
   String SerID = "SerID-" + Thread.currentThread().getId();

   while (true) {
    try {

     String inStr = dis.readUTF();

     // 接收到的文件包含头信息
     if (inStr != null) {
      // 对收到的socket包过滤出文件信息
      if (inStr.contains("ClientInfo")) {
       System.out.println(SerID + " get FileInfo! ");
       // 文件名字
       String fName = new String(inStr.replaceAll(
         "(.+<FileName>)|(<\\/FileName>\\S+)", "")
         .toString().getBytes("utf-8"), "utf-8");
       // 文件总长度
       String fSize = new String(inStr.replaceAll(
         "(.+<FileLength>)|<\\/FileLength>", "")
         .toString().getBytes("utf-8"), "utf-8");
       System.out.println("size: " + fSize);
       long Size = Long.parseLong(fSize);
       // 区块起始长度
       String fPs = new String(
         inStr
           .replaceAll(
             "(.+<FilePointerStart>)|(</FilePointerStart>\\S+)",
             "").toString().getBytes(
             "utf-8"), "utf-8");
       System.out.println("PS: " + fPs);
       // 区块结束长度
       String fPe = new String(
         inStr
           .replaceAll(
             "(.+<FilePointerEnd>)|(</FilePointerEnd>\\S+)",
             "").toString().getBytes(
             "utf-8"), "utf-8");
       System.out.println("PE: " + fPe);
       long PointS = Long.parseLong(fPs); // 分块头
       long PointE = Long.parseLong(fPe); // 分块尾
       System.out.println("SourceFile Name :" + fName);
       File tempF = new File(tempFolder, fName);
       if (!tempF.exists()) {
        //检测目标文件夹是否存在
        if (new File(tempFolder).isDirectory()) {
         TempFile.creat(tempF, Size);// 如果临时文件不存在就建立
        }else {
         boolean creat = new File(tempFolder).mkdirs();
         if (creat) {
          TempFile.creat(tempF, Size);// 如果临时文件不存在就建立
         }else {
          System.out.println("Error:System can not creat folder!");
          System.out.println(SerID+" exits");
          dis.close();// 关闭包类
          dos.close();// 关闭输出流
          s.close();// 关连接
          Thread.currentThread().stop();
         }
        }
        
       }
       // 返回服务器准备好了
       String SerReady = SerID + " ServerReady=1";
       dos.writeUTF(SerReady);// 返回服务器信息
       dos.flush();

       // 取得客户端发送标志"SendStart"
       if (dis.readUTF().equals("SendStart")) {

        // 随机读写文件(适应多线程方式)
        RandomAccessFile fos = new RandomAccessFile(
          tempF.getPath(), "rw");

        long curPoint = PointS;// 文件指针起点
        long endSet = PointE;// 文件指针终点
        long nowSize = 0;// 已读/写字节
        byte[] buffer = new byte[1024]; // 建立缓冲区

        while (curPoint < endSet) {
         int length = 0;
         try {

          if ((endSet - curPoint + 1) < 1024) {
           fos.seek(curPoint);// 寻找写入位置
           byte[] bufferM = new byte[(int) (endSet
             - curPoint + 1)];// 调整缓冲区大小
           length = ins.read(bufferM);// 读取bufferM缓冲socket流

           try {
            fos.write(bufferM);// 将取得的socket流写入文件
            dos.writeUTF("SerGotIt");// 返回服务器信息
            dos.flush();
            curPoint += length;// 文件指针增加
            nowSize += length;
            fos.close();
            // 向发送接收结束标志
            dos.writeUTF("ReciveEnd");
            dos.flush();
            System.out.println(SerID
              + " is receive ok.");
            break;

           } catch (IOException e) {
            e.printStackTrace();
           }
          } else {
           fos.seek(curPoint);
           length = ins.read(buffer);
          }
         } catch (IOException e) {
          e.printStackTrace();
          System.out.println(SerID + " is abnormally closed.");
          break;
         }

         if (length == buffer.length) {
          // 将缓冲区字节写入文件
          try {
           System.out
             .println(SerID
               + " receive "
               + buffer.length
               + " bytes.");
           fos.write(buffer);
           dos.writeUTF("SerGotIt");// 返回服务器信息
           dos.flush();
           curPoint += buffer.length;// 指针+1024
           nowSize += buffer.length;
           System.out.println(SerID + " 指针位置 "
             + curPoint);
           System.out.println(SerID
             + "线程size写入进度:" + nowSize);
          } catch (IOException e) {
           e.printStackTrace();
          }
         }
        }
       }

      }
     }
     // 接收到客户端结束标志,跳出循环
     if (dis.readUTF().equals("SendEnd")) {
      System.out.println("服务器接收完毕");
      break;
     }

    } catch (SocketException s) {
     // s.printStackTrace();
     // 客户端非正常退出处理
     System.out.println(SerID + " is abnormally closed.");
     break;
    }
   }
   dis.close();// 关闭包类
   dos.close();// 关闭输出流
   s.close();// 关连接
   System.out.println(SerID + " exited.");
  } catch (IOException e) {

   e.printStackTrace();
  }

 }
}


文件传输客户端
-----------------------------------------------------------
package FileServer;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.Socket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Description Socket文件传输客户端(默认支持多线程传输,未支持断点续传,未支持内网UDF传输)
 * Creation Date 07-08-2008 9:00
 * @author 卢俊宇
 * @version 1.0
 */
public class TransferClient {

 /**
  * Description 文件传输客户端
  *
  * @param args[0]
  *            文件路径+文件名(例:x:\example\example.class)
  * @param args[1]
  *            服务器IP地址(例: 192.168.1.1)
  * @param args[2]
  *            端口默认2008(例: 2008)
  * @param args[3]
  *            区块长度默认5 (例: 5)
  */
 public static void main(String[] args) {

  int serPort = 2008;// 默认连接端口2008;
  int blockNum = 5;// 文件区块数量(同时决定线程数)
  String serIP = "192.168.1.105";// 服务器IP
  String filePath = "e:\\1.rar";// 欲发送文件路径+文件名

  if (args.length<1 || null==args) {
   System.out.println("采用默认配置连接");
  } else {
   if (args[0].length()>0) {
    filePath = args[0];
   }
   
   if (args[1].length()>0) {
    serIP = args[1];
   }
   if (args[2].length()>0) {
    serPort = Integer.parseInt(args[2]);
   }
   if (args[3].length()>0) {
    blockNum = Integer.parseInt(args[3].replaceAll("\\D", ""));
   }
  }
  System.out.println("文件路径: "+filePath);
  System.out.println("连接IP: "+serIP);
  System.out.println("连接端口: "+serPort);
  System.out.println("线程数: "+blockNum);
  
  // 取得文件信息
  File source = new File(filePath);
  if (!source.exists()) {
   System.out.println("要传输的文件不存在!");
   System.exit(0);
  }

  long fSize = source.length(); // 文件长

  SimpleDateFormat sdf = new SimpleDateFormat("yyMMddhhmmss");
  String currentTime = sdf.format(new Date());

  String fName = currentTime + Math.round(100) + "-" + source.getName();// 按时间生成文件名
  System.out.println("源文件长度 " + fSize+" bytes.");

  // 区块信息
  long blockSize = fSize / blockNum; // 区块长度

  String[] fInfo = new String[blockNum];// 按区块生产文件信息组

  long offset = 0;// 区块起点位置
  long endset = 0;// 区块终点位置
  String sourceFilePath = source.getPath();// 取源文件路径

  // 打包区块信息
  for (int i = 0; i < blockNum; i++) {

   offset = ((long) i) * blockSize;// 设置文件指针起点
   endset = (((long) i + 1) * blockSize - 1 + (i == blockNum - 1
     ? fSize % blockNum
     : 0));// 设置文件指针终点

   fInfo[i] = "ClientInfo<FileName>" + fName + "</FileName>";
   fInfo[i] += "<FilePointerStart>" + offset + "</FilePointerStart>";
   fInfo[i] += "<FilePointerEnd>" + endset + "</FilePointerEnd>";
   fInfo[i] += "<FileLength>" + fSize + "</FileLength>";

   // 按区块开启线程
   new Thread(new FileTransThread(fInfo[i], sourceFilePath, offset, endset,
     serIP, serPort)).start();
  }

 }

}

/**
 * Description 文件传输线程
 *
 * @author 卢俊宇
 * @param info;
 *            初始化时打包的文件信息
 * @param sourceFilePath
 *            文件路径+文件名(例:x:\example\example.class)
 * @param offSet
 *            文件指针起点值地址(按文件区块数量划分)
 * @param endSet
 *            文件指针终点值地址(按文件区块数量划分)
 * @param serPort
 *            默认连接端口2008;
 * @param serIP
 *            连接IP
 * @version 1.1
 */
class FileTransThread implements Runnable {
 private String info;// 文件信息
 private String sourceFilePath;// 源文件路径

 private long offSet;// 这个线程写入文件起始值地址
 private long endSet;// 这个线程写入的文件长度

 private int serPort;// 默认连接端口2008;
 private String serIP;// 连接IP

 FileTransThread(String info, String sourceFilePath, long offSet, long endSet,
   String serIP, int serPort) {
  this.info = info;
  this.sourceFilePath = sourceFilePath;
  this.offSet = offSet;
  this.endSet = endSet;
  this.serIP = serIP;
  this.serPort = serPort;
 }

 public void run() {
  try {
   String CliID = "ClientID-" + Thread.currentThread().getId();
   System.out.println(CliID + " connect " + serIP);
   Socket s = new Socket(InetAddress.getByName(serIP), serPort);
   System.out.println(CliID + " successfully connected.");

   InputStream clientIn = s.getInputStream();
   OutputStream clientOut = s.getOutputStream();

   DataInputStream dis = new DataInputStream(clientIn);

   DataOutputStream dos = new DataOutputStream(clientOut);

   dos.writeUTF(info);// 发送文件信息到服务器
   dos.flush();
   System.out.println(CliID + " send FileInfo!");

   while (true) {

    String inStr = dis.readUTF();
    // 判断服务器是否准备接收
    if (inStr.contains("ServerReady=1")) {
     System.out.println(CliID + " report: " + inStr);
     // 开始准备文件传输

     dos.writeUTF("SendStart");// 发送接收标志
     dos.flush();

     RandomAccessFile fos = new RandomAccessFile(sourceFilePath,
       "r");

     long curPoint = offSet;

     long nowSize = 0;
     byte[] buffer = new byte[1024];

     while (curPoint < endSet) { // 建立缓冲区
      int length = 0;
      try {

       if ((endSet - curPoint + 1) < 1024) {
        fos.seek(curPoint);
        byte[] bufferM = new byte[(int) (endSet
          - curPoint + 1)];// 调整缓冲区大小
        length = fos.read(bufferM);

        try {
         clientOut.write(bufferM);
         clientOut.flush();
         //等待服务器确认
         for(;;){
          if (dis.readUTF().equals("SerGotIt")) {
           break;
          }
         }
         curPoint += length;
         nowSize += length;
         fos.close();
         System.out.println(CliID + " is send ok.");
         break;

        } catch (IOException e) {
         e.printStackTrace();
         System.out.println(CliID + " is abnormally closed.");
         break;

        }
       } else {
        fos.seek(curPoint);
        length = fos.read(buffer);
       }
      } catch (IOException e) {
       e.printStackTrace();

      }

      if (length == buffer.length) {
       // 将缓冲区字节写入文件
       try {
        System.out.println(CliID + " send "
          + buffer.length + " bytes.");
        clientOut.write(buffer);
        clientOut.flush();
        //等待服务器确认
        for(;;){
         if (dis.readUTF().equals("SerGotIt")) {
          break;
         }
        }
        curPoint += buffer.length;// 指针+1024
        nowSize += buffer.length;
        System.out.println(CliID + " 指针位置 " + curPoint);
        System.out.println(CliID + "线程size读入进度:"
          + nowSize);
       } catch (IOException e) {
        e.printStackTrace();
        System.out.println(CliID + " is abnormally closed.");
        break;

       }
      }
     }
    }
    // 向服务端发送结束标志,跳出循环
    if (dis.readUTF().equals("ReciveEnd")) {
     dos.writeUTF("SendEnd");
     dos.flush();
     System.out.println("传输完毕");
     break;
    }
   }
   dis.close();// 关闭包类
   dos.close();// 关闭输出流
   s.close();// 关连接
  } catch (UnknownHostException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

 


生成临时文件
package FileServer;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Description 生成临时文件
 * Creation Date 07-08-2008 9:00
 * @author 卢俊宇
 * @version 1.0
 */
public class TempFile {
 /**
  * 创建文件
  * @param targetFile 文件对象
  * @param fileLength 文件字节长度
  */
 public static void creat(File targetFile, long fileLength) {
  long now = System.currentTimeMillis();
  long length = fileLength;//指定写入文件文件大小
  byte[] buffer = new byte[1024];// 缓冲区1024 bytes
  FileOutputStream fos;
  try {
   fos = new FileOutputStream(targetFile);
   while (true) { // 建立缓冲区
    if (length > 1024) {
     // 将缓冲区字节写入文件
     try {
      fos.write(buffer);// 写入缓冲
      length = length - 1024;
     } catch (IOException e) {
      e.printStackTrace();
     }
    } else {
     byte[] buf = new byte[(int) length];
     System.arraycopy(buffer, 0, buf, 0, (int) length);
     try {
      fos.write(buf);
      fos.close();
     } catch (IOException e) {
      e.printStackTrace();
     }
     break;
    }
   }
   System.out.println("写入临时文件" + targetFile.getName() + ":"
     + targetFile.length() + " bytes");

  } catch (FileNotFoundException e1) {
   e1.printStackTrace();
  }
  long end = System.currentTimeMillis();
  System.out.println("临时文件" + targetFile.getName() + "写入耗时:"
    + (end - now) + " ms");
 }
}


-文件传输包含3个类---------------------------------------------------
效果:我已经测试过该程序了,能成功运行!可以多线程


    FileServer.rar (5.9 KB)
    描述: java源文件
    下载链接:http://dl.iteye.com/topics/download/f28c97a6-91c2-391a-ad95-8fba65a2e088
分享到:
评论

相关推荐

    java多线程网络传输文件(非同步)

    ### Java多线程网络传输文件(非同步) #### 概述 在现代软件开发中,尤其是在涉及大量数据传输的应用场景下,高效的文件传输方案尤为重要。Java作为一种广泛应用的编程语言,提供了丰富的工具和技术来实现高性能...

    java多线程文件传输

    Java多线程文件传输是Java编程中一个重要的实践领域,特别是在大数据处理、网络通信和分布式系统中。在Java中,多线程可以提高程序的执行效率,尤其在处理并发任务时,如大文件的上传、下载和传输。下面将详细探讨...

    java实现多线程文件传输

    在Java编程语言中,实现多线程文件传输是一种优化程序性能、提高系统资源...在提供的`java多线程文件传输`压缩包中,可能包含了实现这些概念的示例代码,通过分析和学习,可以更好地理解多线程文件传输的原理和实践。

    多线程网络文件传输的设计与实现

    在IT领域,多线程网络文件传输是一种常见且复杂的技术挑战。它涉及到多个并发执行的任务,每个任务都可能处理不同的文件部分,同时还需要确保数据的完整性和一致性。在这个设计与实现过程中,我们主要关注以下几个...

    Java多线程文件下载

    Java多线程文件下载是一种高效的下载策略,它通过将大文件分割成多个部分,然后创建多个线程分别下载这些部分,来实现并行下载。这种技术可以显著提高下载速度,尤其是在网络条件不稳定或者带宽有限的情况下。下面...

    java多线程下载文件

    ### Java多线程断点下载文件:关键技术与实现 在当今高速互联网环境下,高效的数据传输技术变得至关重要。Java多线程断点续传文件下载技术就是一种能够显著提高下载速度和稳定性的方法。本文将深入解析Java多线程...

    Java Socket 多线程实现文件传输

    Java Socket 多线程实现文件传输是一个常见的网络编程任务,主要涉及到Java的Socket编程、多线程技术以及文件I/O操作。在这个过程中,服务器端创建一个Socket监听特定端口,等待客户端连接请求。一旦连接建立,双方...

    Java多线程下载器

    Java多线程下载器是一种利用Java编程语言实现的高效文件下载工具,它通过将大文件分割成多个部分并同时下载,显著提高了下载速度。在Java中实现多线程下载器涉及许多关键概念和技术,包括线程、并发控制、网络I/O...

    Java多线程与线程安全实践-基于Http协议的断点续传

    在本项目“Java多线程与线程安全实践-基于Http协议的断点续传”中,我们将深入探讨如何利用Java的多线程机制实现HTTP协议下的断点续传功能,这对于大文件下载或上传的场景尤为实用。 断点续传是一种允许用户在中断...

    JAVA 线程实现数据库的主从同步更新

    在Java编程环境中,...总之,使用Java线程实现数据库主从同步更新是一种常见且实用的技术手段,它涉及到多线程编程、数据库操作、事务管理等多个方面。理解和掌握这些知识点对于开发高可用性的分布式系统至关重要。

    Java多线程与线程安全实践-基于Http协议的断点续传.zip

    总的来说,Java多线程与线程安全实践对于理解和实现基于HTTP协议的断点续传功能至关重要。通过合理地运用多线程、同步机制和原子变量,可以构建出高效、安全的并发应用程序。这个实践项目会深入讲解这些概念,并提供...

    使用java实现网络文件的传输

    使用Java实现网络文件的传输涉及到多个关键知识点,包括Socket编程、多线程处理、文件I/O操作以及基本的安全认证机制。 #### Socket编程基础 在Java中,Socket编程是实现网络通信的基础。`java.net.Socket`类和`...

    Java毕业设计-多线程与线程安全实践-基于Http协议的断点续传.zip

    【标题】"Java毕业设计-多线程与线程安全实践-基于Http协议的断点续传.zip"涉及的核心知识点主要包括Java多线程编程、线程安全、HTTP协议以及文件的断点续传技术。 Java多线程编程是Java语言的一大特性,它允许程序...

    【IT十八掌徐培成】Java基础第21天-05.URL-多线程下载-断点续传-Properties.zip

    Java作为一门广泛使用的编程语言,其在处理网络通信、多线程编程以及文件操作等方面有着丰富的功能。在“【IT十八掌徐培成】Java基础第21天-05.URL-多线程下载-断点续传-Properties.zip”这个压缩包中,主要涵盖了...

    java多线程聊天室

    Java多线程聊天室是一个基于Java编程语言实现的实时通讯应用,它利用多线程技术来处理并发用户连接和通信。在这个项目中,有至少两个关键的类:Server和Control,它们分别扮演着服务器端和客户端控制台的角色。在...

    Java多线程文章系列.pdf

    ### Java多线程文章系列知识点概述 #### 一、Java多线程编程详解 ##### 1. 理解多线程 - **定义**: 多线程是一种机制,允许程序中并行执行多个指令流,每个指令流称为一个线程。 - **特点**: - 线程拥有独立的...

    java多线程下载源代码

    综上所述,Java多线程下载涉及到多线程编程、网络通信、文件操作、并发控制等多个核心Java技术,通过合理设计和优化,可以显著提升下载大文件的效率。在实际开发中,还需要考虑如何将这些概念应用于具体的项目需求,...

    基于Java多线程与线程安全实践-基于Http协议的断点续传

    在IT行业中,Java多线程和线程安全是核心概念,尤其在开发高效、可靠的网络应用程序时。本实践教程将探讨如何在Java中利用多线程实现基于HTTP协议的断点续传功能,这是一个在网络传输大文件时非常有用的技术。 首先...

    java socket多线程文件上传下载实例项目

    Java Socket多线程文件上传下载实例项目是一种基于Java网络编程技术实现的,旨在处理大量并发连接的文件传输服务。在本项目中,Socket是客户端与服务器之间通信的基础,它允许两个应用程序通过网络交换数据。多线程...

Global site tag (gtag.js) - Google Analytics