title: Java Socket实现向云服务器传输文件
date: 2019-08-06 08:34:52
tags:

  • socket
  • java
  • 云服务器
  • 阿里云
  • ubuntu
    categories:
  • java

前一段时间因为项目需要,用了阿里的云服务器,需要模拟数据文件传送到服务器的一个过程。一直以来都觉得服务器是非常神秘的东西,如果没有需要的话,也不会尝试在本地向服务器传输文件。一开始查了很多资料,都说要写两个程序,一个要在服务器端先运行,一个在客户端上运行。但其实一直都不知道服务器上怎么运行Java程序,后来发现服务器就像电脑一样。如果是Ubuntu的云服务器类似Linux系统,要是Windows Server云服务器就像Windows电脑一样,运行Java程序,打成jar包,或者直接在终端编译,运行。

操作系统:*Win10*
*使用的软件:
Xshell(连接云服务器),Xftp(可以向服务器中传文件)***

云服务器:*阿里云 + Ubuntu18(选择什么样的系统其实没关系)**
服务器配置:需要安装 jdk (我安装的是1.8,1.7应该也都可以),安全组中配置开放要监听的端口号(注意不要和其他程序冲突)*

因为使用Java实现向云服务器传送文件,需要先在服务器端运行服务器端的程序,所以需要安装 jdk 。

服务器端程序:
注意:如果采取直接在命令行编译,运行的话。程序不要带包名,并且注意程序的编码格式。特别的:如果使用eclipse编写的程序,直接放入服务器端运行会报非法字符的bug,需要用Notepad++打开,把编码格式转为utf-8格式。(其他编码问题,比如用idea打开eclipse的工程,也可以使用这种方法解决。)

    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      143
      144
      145
      146
      147
      148
      149
      150
      151
      152
      153
      154
      155
      156
      157
      158
      159
      160
      161
      162
      163
      164
      165
      166
      167
      168
      169
      170
      171
      172
      173
      174
      `import java.io.DataInputStream;`
      `import java.io.File;`
      `import java.io.FileOutputStream;`
      `import java.io.OutputStream;`
      `import java.math.RoundingMode;`
      `import java.net.ServerSocket;`
      `import java.net.Socket;`
      `import java.text.DecimalFormat;`
      `import java.util.Date;`
      `import java.text.SimpleDateFormat;`

      `/**`

      - `服务器文件传输Server端`
      `*/`
      `public class FileTransferServer extends ServerSocket {`

      `private static final int SERVER_PORT = 89; // 服务端端口,根据需要改写,注意安全组要开放端口`

      `private static DecimalFormat df = null;`

      `static {`
      // 设置数字格式,保留一位有效小数
      df = new DecimalFormat("#0.0");
      df.setRoundingMode(RoundingMode.HALF_UP);
      df.setMinimumFractionDigits(1);
      df.setMaximumFractionDigits(1);
      `}`

      `public FileTransferServer() throws Exception {`
      super(SERVER_PORT);
      `}`

      `/**`

      - `使用线程处理每个客户端传输的文件`
      `*/`
      `public void load() throws Exception {`
      `int i=0;`
      `while (true) {`
      // server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的
      Socket socket = this.accept();
      //System.out.println("链接成功!");
      /**
      - `服务端处理客户端的连接请求是同步进行的, 每次接收到来自客户端的连接请求后,`
      - `都要先跟当前的客户端通信完之后才能再处理下一个连接请求。 这在并发比较多的情况下会严重影响程序的性能`
      - `为此可以把它改为如下这种异步处理与客户端通信的方式`
      `/`
      // 每接收到一个Socket就建立一个新的线程来处理它
      Thread thread=new Thread(new Task(socket),"客户端:"+i++);
      thread.start();
      System.out.println(Thread.currentThread().getName()+" 链接成功!");
      //new Thread(new Task(socket)).start();
      `}`
      `}`

      `/**`

      - `处理客户端传输过来的文件线程类`
      `*/`
      `class Task implements Runnable {`

      `private Socket socket;`

      `private DataInputStream dis;`

      `private FileOutputStream fos;`

      `public Task(Socket socket) {`
      this.socket = socket;
      `}`

      `@Override`
      `public void run() {`
      OutputStream os = null;
      try {
      boolean flag = true;
      do {
      dis = new DataInputStream(socket.getInputStream());

      // 文件名和长度
      String fileName = dis.readUTF();
      long fileLength = dis.readLong();
      //路径按自己的情况改写
      File directory = new File("/root/接收/"+Thread.currentThread().getName());
      if(!directory.exists()) {
      directory.mkdir();//如果存储文件夹不存在则创建子目录
      }
      //获得前缀名
      String formername = fileName.substring(0, fileName.indexOf("."));
      //获取后缀名
      String sname = fileName.substring(fileName.lastIndexOf("."));
      //时间格式化
      SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
      //获取当前时间并作为时间戳
      String timeStamp=df.format(new Date());
      //拼接新的文件名
      String newName = formername+timeStamp+sname;

      ​ File file = new File(directory.getAbsolutePath() + File.separatorChar + newName);
      fos = new FileOutputStream(file);

      // 开始接收文件
      byte[] bytes = new byte[1024];
      int length = 0;

      while((length = dis.read(bytes, 0, bytes.length)) != -1) {
      fos.write(bytes, 0, length);
      fos.flush();
      }

      ​ System.out.println("接收到 '"+Thread.currentThread().getName()+
      " '传来的文件 文件名:"+newName);
      System.out.println("文件大小:"+getFormatFileSize(fileLength));
      //向客户端反馈信息,将信息储存在数据缓冲区中
      os = socket.getOutputStream();
      os.write("您发送的文件已经被接收".getBytes());
      os.flush();
      dis = null;
      }while(flag);
      } catch (Exception e) {
      e.printStackTrace();
      } finally {
      try {
      if(os != null)
      os.close();
      if(fos != null)
      fos.close();
      if(dis != null)
      dis.close();
      socket.close();
      } catch (Exception e) {

      ​ }
      }
      `}`
      `}`

      `/**`

      - `格式化文件大小`
      - `@param length`
      - `@return`
      `*/`
      `private String getFormatFileSize(long length) {`
      `double size = ((double) length) / (1 << 30);`
      `if(size >= 1) {`
      return df.format(size) + "GB";
      `}`
      `size = ((double) length) / (1 << 20);`
      `if(size >= 1) {`
      return df.format(size) + "MB";
      `}`
      `size = ((double) length) / (1 << 10);`
      `if(size >= 1) {`
      return df.format(size) + "KB";
      `}`
      `return length + "B";`
      `}`

      `/**`

      - `入口`
      - `@param args`
      `*/`
      `public static void main(String[] args) {`
      `try {`
      FileTransferServer server = new FileTransferServer(); // 启动服务端
      server.load();
      `} catch (Exception e) {`
      e.printStackTrace();
      `}`
      `}`
      `}`

正常在这段代码服务器端运行之后,在服务器端不会马上有什么显示,需要客户端运行程序,连接才算是建立上了。

客户端程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package SimpleSocket;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.math.RoundingMode;
import java.net.Socket;
import java.text.DecimalFormat;
import java.util.Scanner;

/**
* 服务器文件传输Client端
*/
public class FileTransferClient extends Socket {

private static final String SERVER_IP = "11.11.111.111"; // 服务器的公网IP地址
private static final int SERVER_PORT = 89; // 服务端端口,要和之前服务器端监听的端口一致

private Socket client;

private FileInputStream fis;

private DataOutputStream dos;
private static DecimalFormat df = null;
static {
// 设置数字格式,保留一位有效小数
df = new DecimalFormat("#0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
df.setMinimumFractionDigits(1);
df.setMaximumFractionDigits(1);
}

/**
* 构造函数
* 与服务器建立连接
*/
public FileTransferClient() throws Exception {
super(SERVER_IP, SERVER_PORT);
this.client = this;
System.out.println("Cliect[port:" + client.getLocalPort() + "] 成功连接服务端");
}

/**
* 向服务端传输文件
* @throws Exception
*/
public void sendFile() throws Exception {
FileInputStream fis = null;
InputStream io = null;
try {
boolean flag = true;
do {
Scanner sc = new Scanner(System.in);

System.out.println("请输入地址:");
String s = sc.next();
File file = new File(s);

fis = new FileInputStream(file);
dos = new DataOutputStream(client.getOutputStream());

// 文件名和长度
dos.writeUTF(file.getName());
dos.flush();
dos.writeLong(file.length());
dos.flush();


// 开始传输文件
System.out.println("======== 开始传输文件 ========");

long startTime = System.currentTimeMillis();
byte[] bytes = new byte[1024];
int length = 0;
long progress = 0;

while((length = fis.read(bytes, 0, bytes.length)) != -1) {
dos.write(bytes, 0, length);
dos.flush();
progress += length;
System.out.print("| " + (100*progress/file.length()) + "% |");
}
long endTime = System.currentTimeMillis();
System.out.println();
System.out.println("======== 文件传输成功 ========");

System.out.println("文件大小:"+getFormatFileSize(file.length())+" 耗时:"+(endTime - startTime)+"ms");
//这行服务器端我发送的数据完毕。

fis = null;
}while(flag);

io = client.getInputStream();
byte[] b1=new byte[1024];
int len1;
while((len1=io.read(b1))!=-1){
String str=new String(b1, 0, len1);
System.out.println(str);
}

}catch (Exception e) {
e.printStackTrace();
} finally {
if(io!=null)
io.close();
if(fis != null)
fis.close();
if(dos != null)
dos.close();
client.close();
}
}
/**
* 格式化文件大小
* @param length
* @return
*/
private String getFormatFileSize(long length) {
double size = ((double) length) / (1 << 30);
if(size >= 1) {
return df.format(size) + "GB";
}
size = ((double) length) / (1 << 20);
if(size >= 1) {
return df.format(size) + "MB";
}
size = ((double) length) / (1 << 10);
if(size >= 1) {
return df.format(size) + "KB";
}
return length + "B";
}
/**
* 入口
* @param args
*/
public static void main(String[] args) {
try {
FileTransferClient client = new FileTransferClient(); // 启动客户端连接
//Thread.sleep(60000*10);
client.sendFile(); // 传输文件
Thread.sleep(60000*10);
} catch (Exception e) {
e.printStackTrace();
}
}
}

客户端运行程序后,需要输入你所要传输的文件路径,然后传输。

成功建立连接:

服务器端:

客户端:

成功传输文件:

客户端:

服务器端:

© 2021 XuXing's blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero