最近學(xué)Socket學(xué)上癮了,就寫了一個(gè)簡(jiǎn)單的文件傳輸程序。
客戶端設(shè)計(jì)思路:客戶端與服務(wù)端建立連接,選擇客戶端本地文件,先將文件名及大小等屬性發(fā)送給服務(wù)端,再將文件通過(guò)流的方式傳輸給服務(wù)端。傳輸?shù)倪M(jìn)度打印到控制臺(tái)中,直到傳輸完成。
服務(wù)端設(shè)計(jì)思路:服務(wù)端接收客戶端的請(qǐng)求(阻塞式),每接收到一個(gè)客戶端請(qǐng)求連接后,就新開(kāi)一個(gè)處理文件的線程,開(kāi)始寫入流,將文件到服務(wù)器的指定目錄下,并與傳輸過(guò)來(lái)的文件同名。
下面是客戶端和服務(wù)端的代碼實(shí)現(xiàn):
客戶端代碼:
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
|
import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.net.Socket; /** * 文件傳輸Client端<br> * 功能說(shuō)明: * * @author 大智若愚的小懂 * @Date 2016年09月01日 * @version 1.0 */ public class FileTransferClient extends Socket { private static final String SERVER_IP = "127.0.0.1" ; // 服務(wù)端IP private static final int SERVER_PORT = 8899 ; // 服務(wù)端端口 private Socket client; private FileInputStream fis; private DataOutputStream dos; /** * 構(gòu)造函數(shù)<br/> * 與服務(wù)器建立連接 * @throws Exception */ public FileTransferClient() throws Exception { super (SERVER_IP, SERVER_PORT); this .client = this ; System.out.println( "Cliect[port:" + client.getLocalPort() + "] 成功連接服務(wù)端" ); } /** * 向服務(wù)端傳輸文件 * @throws Exception */ public void sendFile() throws Exception { try { File file = new File( "E:\\JDK1.6中文參考手冊(cè)(JDK_API_1_6_zh_CN).CHM" ); if (file.exists()) { fis = new FileInputStream(file); dos = new DataOutputStream(client.getOutputStream()); // 文件名和長(zhǎng)度 dos.writeUTF(file.getName()); dos.flush(); dos.writeLong(file.length()); dos.flush(); // 開(kāi)始傳輸文件 System.out.println( "======== 開(kāi)始傳輸文件 ========" ); 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()) + "% |" ); } System.out.println(); System.out.println( "======== 文件傳輸成功 ========" ); } } catch (Exception e) { e.printStackTrace(); } finally { if (fis != null ) fis.close(); if (dos != null ) dos.close(); client.close(); } } /** * 入口 * @param args */ public static void main(String[] args) { try { FileTransferClient client = new FileTransferClient(); // 啟動(dòng)客戶端連接 client.sendFile(); // 傳輸文件 } catch (Exception e) { e.printStackTrace(); } } } |
服務(wù)端代碼:
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
|
import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.math.RoundingMode; import java.net.ServerSocket; import java.net.Socket; import java.text.DecimalFormat; /** * 文件傳輸Server端<br> * 功能說(shuō)明: * * @author 大智若愚的小懂 * @Date 2016年09月01日 * @version 1.0 */ public class FileTransferServer extends ServerSocket { private static final int SERVER_PORT = 8899 ; // 服務(wù)端端口 private static DecimalFormat df = null ; static { // 設(shè)置數(shù)字格式,保留一位有效小數(shù) df = new DecimalFormat( "#0.0" ); df.setRoundingMode(RoundingMode.HALF_UP); df.setMinimumFractionDigits( 1 ); df.setMaximumFractionDigits( 1 ); } public FileTransferServer() throws Exception { super (SERVER_PORT); } /** * 使用線程處理每個(gè)客戶端傳輸?shù)奈募? * @throws Exception */ public void load() throws Exception { while ( true ) { // server嘗試接收其他Socket的連接請(qǐng)求,server的accept方法是阻塞式的 Socket socket = this .accept(); /** * 我們的服務(wù)端處理客戶端的連接請(qǐng)求是同步進(jìn)行的, 每次接收到來(lái)自客戶端的連接請(qǐng)求后, * 都要先跟當(dāng)前的客戶端通信完之后才能再處理下一個(gè)連接請(qǐng)求。 這在并發(fā)比較多的情況下會(huì)嚴(yán)重影響程序的性能, * 為此,我們可以把它改為如下這種異步處理與客戶端通信的方式 */ // 每接收到一個(gè)Socket就建立一個(gè)新的線程來(lái)處理它 new Thread( new Task(socket)).start(); } } /** * 處理客戶端傳輸過(guò)來(lái)的文件線程類 */ class Task implements Runnable { private Socket socket; private DataInputStream dis; private FileOutputStream fos; public Task(Socket socket) { this .socket = socket; } @Override public void run() { try { dis = new DataInputStream(socket.getInputStream()); // 文件名和長(zhǎng)度 String fileName = dis.readUTF(); long fileLength = dis.readLong(); File directory = new File( "D:\\FTCache" ); if (!directory.exists()) { directory.mkdir(); } File file = new File(directory.getAbsolutePath() + File.separatorChar + fileName); fos = new FileOutputStream(file); // 開(kāi)始接收文件 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( "======== 文件接收成功 [File Name:" + fileName + "] [Size:" + getFormatFileSize(fileLength) + "] ========" ); } catch (Exception e) { e.printStackTrace(); } finally { try { 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(); // 啟動(dòng)服務(wù)端 server.load(); } catch (Exception e) { e.printStackTrace(); } } } |
測(cè)試的結(jié)果(客戶端):
測(cè)試的結(jié)果(服務(wù)端):
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://blog.csdn.net/huang930528/article/details/52401565