Java Socket 多线程网络传输多个文件

由于需要研究了下用 java socket 传输文件,由于需要传输多个文件,因此,采用了多线程设计。客户端每个线程创建一个 socket 连接,每个 socket 连接负责传输一个文件,服务端的ServerSocket每次 accept 一个 socket 连接,创建一个线程用于接收客户端传来的文件。

1、服务端

[java]  view plain copy
  1. import java.io.BufferedInputStream;    
  2. import java.io.BufferedOutputStream;    
  3. import java.io.DataInputStream;    
  4. import java.io.DataOutputStream;    
  5. import java.io.FileOutputStream;    
  6. import java.net.ServerSocket;    
  7. import java.net.Socket;    
  8. import java.util.concurrent.ExecutorService;    
  9. import java.util.concurrent.Executors;    
  10.     
  11. public class TransferServer {    
  12.     
  13.     private int defaultBindPort = Constants.DEFAULT_BIND_PORT;    //默认监听端口号为10000    
  14.     private int tryBindTimes = 0;           //初始的绑定端口的次数设定为0    
  15.         
  16.     private ServerSocket serverSocket;      //服务套接字等待对方的连接和文件发送    
  17.         
  18.     private ExecutorService executorService;    //线程池    
  19.     private final int POOL_SIZE = 4;            //单个CPU的线程池大小     
  20.         
  21.     /**  
  22.      * 不带参数的构造器,选用默认的端口号  
  23.      * @throws Exception  
  24.      */    
  25.     public TransferServer() throws Exception{    
  26.         try {    
  27.             this.bingToServerPort(defaultBindPort);    
  28.             executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);    
  29.             System.out.println("开辟线程数 : " + Runtime.getRuntime().availableProcessors() * POOL_SIZE);    
  30.         } catch (Exception e) {    
  31.             throw new Exception("绑定端口不成功!");    
  32.         }    
  33.     }    
  34.         
  35.     /**  
  36.      * 带参数的构造器,选用用户指定的端口号  
  37.      * @param port  
  38.      * @throws Exception  
  39.      */    
  40.     public TransferServer(int port) throws Exception{    
  41.         try {    
  42.             this.bingToServerPort(port);    
  43.             executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);    
  44.         } catch (Exception e) {    
  45.             throw new Exception("绑定端口不成功!");    
  46.         }    
  47.     }    
  48.         
  49.     private void bingToServerPort(int port) throws Exception{    
  50.         try {    
  51.             serverSocket = new ServerSocket(port);    
  52.             System.out.println(port);    
  53.             System.out.println("服务启动!");    
  54.         } catch (Exception e) {    
  55.             this.tryBindTimes = this.tryBindTimes + 1;    
  56.             port = port + this.tryBindTimes;    
  57.             if(this.tryBindTimes >= 20){    
  58.                 throw new Exception("您已经尝试很多次了,但是仍无法绑定到指定的端口!请重新选择绑定的默认端口号");    
  59.             }    
  60.             //递归绑定端口    
  61.             this.bingToServerPort(port);    
  62.         }    
  63.     }    
  64.         
  65.     public void service(){    
  66.         Socket socket = null;    
  67.         while (true) {    
  68.             try {    
  69.                 socket = serverSocket.accept();    
  70.                 executorService.execute(new Handler(socket));    
  71.             } catch (Exception e) {    
  72.                 e.printStackTrace();    
  73.             }    
  74.         }    
  75.     }    
  76.         
  77.     
  78.     class Handler implements Runnable{    
  79.         private Socket socket;    
  80.             
  81.         public Handler(Socket socket){    
  82.             this.socket = socket;    
  83.         }    
  84.     
  85.         public void run() {    
  86.                 
  87.             System.out.println("New connection accepted " + socket.getInetAddress() + ":" + socket.getPort());    
  88.                 
  89.             DataInputStream dis = null;    
  90.             DataOutputStream dos = null;    
  91.     
  92.             int bufferSize = 8192;    
  93.             byte[] buf = new byte[bufferSize];    
  94.                 
  95.             try {    
  96.                 dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));    
  97.                 String savePath = Constants.RECEIVE_FILE_PATH + dis.readUTF();    
  98.                 long length = dis.readLong();    
  99.                 dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(savePath)));    
  100.                     
  101.                 int read = 0;    
  102.                 long passedlen = 0;    
  103.                 while ((read = dis.read(buf)) != -1) {    
  104.                     passedlen += read;    
  105.                     dos.write(buf, 0, read);    
  106.                     System.out.println("文件[" + savePath + "]已经接收: " + passedlen * 100L/ length + "%");    
  107.                 }    
  108.                 System.out.println("文件: " + savePath + "接收完成!");    
  109.                     
  110.             } catch (Exception e) {    
  111.                 e.printStackTrace();    
  112.                 System.out.println("接收文件失败!");    
  113.             }finally{    
  114.                 try {    
  115.                     if(dos != null){    
  116.                         dos.close();    
  117.                     }    
  118.                     if(dis != null){    
  119.                         dis.close();    
  120.                     }    
  121.                     if(socket != null){    
  122.                         socket.close();    
  123.                     }    
  124.                 } catch (Exception e) {    
  125.                     e.printStackTrace();    
  126.                 }    
  127.             }    
  128.         }    
  129.     }    
  130.         
  131.     public static void main(String[] args) throws Exception{    
  132.         new TransferServer().service();    
  133.     }    
  134. }   
2、客户端

[java]  view plain copy
  1. import java.io.BufferedInputStream;    
  2. import java.io.DataInputStream;    
  3. import java.io.DataOutputStream;    
  4. import java.io.File;    
  5. import java.io.FileInputStream;    
  6. import java.net.Socket;    
  7. import java.util.ArrayList;    
  8. import java.util.Random;    
  9. import java.util.Vector;    
  10. import java.util.concurrent.ExecutorService;    
  11. import java.util.concurrent.Executors;    
  12.     
  13.     
  14. public class TransferClient {    
  15.     
  16.     private static ArrayList<String> fileList = new ArrayList<String>();    
  17.         
  18.     private String sendFilePath = Constants.SEND_FILE_PATH;    
  19.         
  20.     /**  
  21.      * 带参数的构造器,用户设定需要传送文件的文件夹  
  22.      * @param filePath  
  23.      */    
  24.     public TransferClient(String filePath){    
  25.         getFilePath(filePath);    
  26.     }    
  27.         
  28.     /**  
  29.      * 不带参数的构造器。使用默认的传送文件的文件夹  
  30.      */    
  31.     public TransferClient(){    
  32.         getFilePath(sendFilePath);    
  33.     }    
  34.         
  35.     public void service(){    
  36.         ExecutorService executorService = Executors.newCachedThreadPool();    
  37.         Vector<Integer> vector = getRandom(fileList.size());    
  38.         for(Integer integer : vector){    
  39.             String filePath = fileList.get(integer.intValue());    
  40.             executorService.execute(sendFile(filePath));    
  41.         }    
  42.     }    
  43.         
  44.     
  45.     private void getFilePath(String dirPath){    
  46.         File dir = new File(dirPath);    
  47.         File[] files = dir.listFiles();    
  48.         if(files == null){    
  49.             return;    
  50.         }    
  51.         for(int i = 0; i < files.length; i++){    
  52.             if(files[i].isDirectory()){    
  53.                 getFilePath(files[i].getAbsolutePath());    
  54.             }    
  55.             else {    
  56.                 fileList.add(files[i].getAbsolutePath());    
  57.             }    
  58.         }    
  59.     }    
  60.         
  61.     private Vector<Integer> getRandom(int size){    
  62.         Vector<Integer> v = new Vector<Integer>();    
  63.         Random r = new Random();    
  64.         boolean b = true;    
  65.         while(b){    
  66.             int i = r.nextInt(size);    
  67.             if(!v.contains(i))    
  68.                 v.add(i);    
  69.             if(v.size() == size)    
  70.                 b = false;    
  71.         }    
  72.         return v;    
  73.     }        
  74.         
  75.     private static Runnable sendFile(final String filePath){    
  76.         return new Runnable(){    
  77.                 
  78.             private Socket socket = null;    
  79.             private String ip ="localhost";    
  80.             private int port = 10000;    
  81.                 
  82.             public void run() {    
  83.                 System.out.println("开始发送文件:" + filePath);    
  84.                 File file = new File(filePath);    
  85.                 if(createConnection()){    
  86.                     int bufferSize = 8192;    
  87.                     byte[] buf = new byte[bufferSize];    
  88.                     try {    
  89.                         DataInputStream fis = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath)));    
  90.                         DataOutputStream dos = new DataOutputStream(socket.getOutputStream());    
  91.                             
  92.                         dos.writeUTF(file.getName());    
  93.                         dos.flush();    
  94.                         dos.writeLong(file.length());    
  95.                         dos.flush();    
  96.                             
  97.                         int read = 0;    
  98.                         int passedlen = 0;    
  99.                         long length = file.length();    //获得要发送文件的长度    
  100.                         while ((read = fis.read(buf)) != -1) {    
  101.                             passedlen += read;    
  102.                             System.out.println("已经完成文件 [" + file.getName() + "]百分比: " + passedlen * 100L/ length + "%");    
  103.                             dos.write(buf, 0, read);    
  104.                         }    
  105.     
  106.                        dos.flush();    
  107.                        fis.close();    
  108.                        dos.close();    
  109.                        socket.close();    
  110.                        System.out.println("文件 " + filePath + "传输完成!");    
  111.                     } catch (Exception e) {    
  112.                         e.printStackTrace();    
  113.                     }    
  114.                 }    
  115.             }    
  116.                 
  117.             private boolean createConnection() {    
  118.                 try {    
  119.                     socket = new Socket(ip, port);    
  120.                     System.out.println("连接服务器成功!");    
  121.                     return true;    
  122.                 } catch (Exception e) {    
  123.                     System.out.println("连接服务器失败!");    
  124.                     return false;    
  125.                 }     
  126.             }    
  127.                 
  128.         };    
  129.     }    
  130.         
  131.     public static void main(String[] args){    
  132.         new TransferClient().service();    
  133.     }    
  134. }  

3、常量类

[java]  view plain copy
  1. public interface Constants {    
  2.     
  3.     public final static String RECEIVE_FILE_PATH = "E:\\receive\\";    
  4.         
  5.     public final static String SEND_FILE_PATH = "E:\\send";    
  6.         
  7.     public final static int DEFAULT_BIND_PORT = 10000;    
  8. }    
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值