over 4 years ago

0. 前言

今天要實做一個 Client-Server 網路程式,利用 Socket 類別透過網路傳送資料!
資料類型可以是字串也可以是檔案!
重要的是,伺服器端和客戶端傳送的訊息類型要對稱,以達成協議,意思是客戶端傳送 int 資料伺服器就要接收 int 資料; 客戶端傳送字串,伺服器端就需要接收字串!

1. 伺服器端

建立伺服器端程式,以等待接收客戶端所要求的訊息。

1.1 建立連線

1.1.1 引用類別

java.net.InetAddress
java.net.ServerSocket
java.net.Socket

1.1.2 程式範例
SocketServer.java
private final int PORT = 12345;
private final String IP = "127.0.0.1";
// 讓 serverSocket 可以綁訂固定 ip 
InetAddress addr = InetAddress.getByName(IP);
ServerSocket serverSocket = new ServerSocket(PORT, 5, addr);
Socket socket = serverSocket.accept();

1.2 接收要求訊息,以 字串串流 為例

1.2.1 引用類別

java.io.InputStreamReader
java.io.BufferedReader

1.2.2 程式範例
SocketServer.java
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = br.readLine();

1.3 傳送回應要求,以 字串串流 為例

1.3.1 引用類別

java.io.OutputStreamWriter
java.io.BufferedWriter

1.3.2 程式範例
SocketServer.java
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 輸出字串
bw.write(string);
// 輸出換行
bw.newLine();
// 沖出訊息
bw.flush();

1.4 接收要求,以 檔案串流 為例

1.4.1 引用類別

java.io.DataInputStream

1.4.2 接收串流,程式範例
SocketServer.java
BufferedInputStream bis = new BufferedInputStream(socket.getOutputStream());
DataInputStream dis = new DataInputStream(bos);

// 以下為讀取整數,例:檔案數量
int fileNumber = dis.readInt();
// 以下為讀取長整數,例:檔案大小
long length = dis.readLong();
// 以下為讀取以 utf 為編碼的字串,例:檔案名稱
String fileName = dis.readUTF();
// 以下為讀取檔案內容
byte[] buf = new byte[1];
// 讀取串流中部份資料至 buf Byte 陣列中暫存
// index 若為 -1 則表示讀到檔案結束位置,否則每次讀取的內容大小,目前陣列大小為 1,則內容大小為 1 
long passedLength = 0L;
while(true){
  // 從網路串流讀取資料至 buf byte 陣列暫存
    int index = dis.read(buf);
  passedLength += index;
  if(passedLength >= length){
    break;
  }
  // 寫入檔案,請參考 1.4.4 程式範例說明
  // 將暫存陣列的資料寫至檔案串流, 存檔
  dos.write(buf, 0, index);
  dos.flush(); // 寫出
}
1.4.3 引用類別

java.io.File
java.io.FileOutputStream

1.4.4 存檔,程式範例
SocketServer.java
// 將檔案存入 D:\\
File file = new File("D:\\" + fileName);
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
// 變數 buf,index 請參考 1.4.2 程式範例說明
dos.write(buf, 0, index);
// 關閉串流
dos.close();

2. 客戶端

2.1 引用類別

java.net.Socket
java.io.BufferedWriter
java.io.DataOutputStream

2.2 建立連線

SocketClient.java
Socket socket;
try {
    socket = new Socket("127.0.0.1", 12345);
}catch(UnknownHostException e){
    e.printStackTrace();
}catch(IOException e){
    e.printStackTrace();
}finally {
    try {
        socket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

2.3 傳輸要求訊息,以 字串串流 為例

SocketClient.java
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String string = "Hello world";
// 輸出字串
bw.write(string);
// 輸出換行
bw.newLine();
// 沖出訊息
bw.flush();  // 傳送出

2.4 傳輸要求訊息,以 檔案串流 為例

SocketClient.java
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dos = new DataOutputStream(bos);
// 傳送檔名以 utf 為編碼
dos.writeUTF(file.getName());
dos.flush(); // 傳送出
// 傳送檔案大小
dos.writeLong((long) file.length());
dos.flush(); // 傳送出

// 讀擋
File file = new File("D:\\happy.mp3"):
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);

// 傳送檔案內容
byte[] buf = new byte[4096];
while(true){
  // 讀取檔案內容至 buf byte 陣列暫存
  int index = dis.read(buf);
  if(index == -1) break;
  // 從 buf 暫存陣列讀取資料至網路串流 
  dos.write(buf, 0, index);  
  dos.flush(); // 傳送出
}
// 關閉串流
dis.close();
dos.close();

3. 加密傳輸 SSL、TLS

← Apache Maven - 建構 Dependency 關聯圖 Java 網路程式 Web Service SOAP 客戶端 - HTTP Post 版 →
 
comments powered by Disqus