Java 網絡程式設計
網絡程式設計是指編寫運作在多個裝置(計算機)的程式,這些裝置都通過網絡連接配接起來。
java.net 包中 J2SE 的 API 包含有類和接口,它們提供低層次的通信細節。你可以直接使用這些類和接口,來專注于解決問題,而不用關注通信細節。
java.net 包中提供了兩種常見的網絡協定的支援:
TCP:TCP 是傳輸控制協定的縮寫,它保障了兩個應用程式之間的可靠通信。通常用于網際網路協定,被稱 TCP / IP。
面向連接配接(三次握手),資料安全,速度略低,分為用戶端和服務端
三次握手:用戶端先向服務端發起請求,服務端響應請求,傳輸資料
UDP:UDP 是使用者資料報協定的縮寫,一個無連接配接的協定。提供了應用程式之間要發送的資料的資料包。
面向連接配接,資料不安全,速度快,不區分用戶端和服務端
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csUzZE9EeFRUTyUkeYhnRzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuUjMzIDNzQTMxIzNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
Socket 程式設計
套接字使用TCP提供了兩台計算機之間的通信機制。 用戶端程式建立一個套接字,并嘗試連接配接伺服器的套接字。
當連接配接建立時,伺服器會建立一個 Socket 對象。用戶端和伺服器現在可以通過對 Socket 對象的寫入和讀取來進行通信。
java.net.Socket 類代表一個套接字,并且 java.net.ServerSocket 類為伺服器程式提供了一種來監聽用戶端,并與他們建立連接配接的機制。
以下步驟在兩台計算機之間使用套接字建立TCP連接配接時會出現:
- 伺服器執行個體化一個 ServerSocket 對象,表示通過伺服器上的端口通信。
- 伺服器調用 ServerSocket 類的 accept() 方法,該方法将一直等待,直到用戶端連接配接到伺服器上給定的端口。
- 伺服器正在等待時,一個用戶端執行個體化一個 Socket 對象,指定伺服器名稱和端口号來請求連接配接。
-
Socket 類的構造函數試圖将用戶端連接配接到指定的伺服器和端口号。如果通信被建立,則在用戶端建立一個 Socket
對象能夠與伺服器進行通信。
- 在伺服器端,accept() 方法傳回伺服器上一個新的 socket 引用,該 socket 連接配接到用戶端的 socket。
連接配接建立後,通過使用 I/O 流在進行通信,每一個socket都有一個輸出流和一個輸入流,用戶端的輸出流連接配接到伺服器端的輸入流,而用戶端的輸入流連接配接到伺服器端的輸出流。
TCP 是一個雙向的通信協定,是以資料可以通過兩個資料流在同一時間發送.以下是一些類提供的一套完整的有用的方法來實作 socket。
網絡程式設計(練習)
用戶端
package com.udp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Test1_Client {
/*
* 用戶端向伺服器寫入字元串(鍵盤錄入),伺服器(多線程)将字元串反轉後寫回,用戶端讀取到的是反轉後的字元串
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Scanner sc = new Scanner(System.in); // 建立鍵盤錄入對象
Socket socket = new Socket("127.0.0.1",54321);//建立用戶端,指定ip位址和端口号
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //擷取輸入法
PrintStream ps = new PrintStream(socket.getOutputStream()); //擷取輸出流
ps.println(sc.nextLine());//将字元串寫到伺服器去
System.out.println(br.readLine()); //将反轉後的結果讀出來
}
}
服務端
package com.udp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.zip.InflaterInputStream;
public class Test1_Server {
public static void main(String[] args) throws IOException {
/*
* 用戶端向伺服器寫入字元串(鍵盤錄入),伺服器(多線程)将字元串反轉後寫回,用戶端讀取到的是反轉後的字元串
*/
ServerSocket server = new ServerSocket(54321);
System.out.println("伺服器啟動,綁定54321端口");
while(true) {
final Socket socket = server.accept(); //接受用戶端的請求
new Thread() {
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream()); //擷取輸出流
String line = br.readLine(); //将用戶端寫過來的資料讀取出來
line = new StringBuilder(line).reverse().toString(); //鍊式程式設計
ps.println(line);
socket.close();
}catch (IOException e ) {
e.printStackTrace();
}
}
}.start();
}
}
}
練習(用戶端向伺服器上傳檔案)
用戶端
package com.udp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Test2_UpdataClient {
public static void main(String[] args) throws UnknownHostException, IOException {
//1.提示輸入要上傳的檔案路徑,驗證路徑是否存在以及是否是檔案夾
File file = getFile();
//2.發送檔案名到服務端
Socket socket = new Socket("127.0.0.1",12345);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(file.getName());
//6.接收結果,如果存在給與提示,程式直接退出
String result = br.readLine();
if("存在".equals(result)) {
System.out.println("您上傳的檔案已經存在請不要重複上傳");
socket.close();
return;
}
//7.如果不存在,定義FileInputStrean讀取檔案,寫到網絡
FileInputStream fis = new FileInputStream(file);
byte[] arr = new byte[8192];
int len;
while((len = fis.read(arr)) != -1) {
ps.write(arr,0,len);
}
fis.close();
socket.close();
}
private static File getFile() {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個檔案路徑:");
while(true ) {
String line = sc.nextLine();
File file = new File(line);
if(!file.exists()) {
System.out.println("您錄入的檔案路徑不存在,請輸入");
}
}
return null;
}
}
伺服器
package com.udp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Test2_UpdataServer {
private static ServerSocket server;
public static void main(String[] args) throws IOException {
//3.建立多線程
ServerSocket sercer = new ServerSocket(12345);
System.out.println("伺服器啟動,綁定12345端口号");
//4.讀取檔案名
while(true) {
final Socket socket = server.accept();
new Thread() {
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
PrintStream ps = new PrintStream(socket.getOutputStream());
String fileName = br.readLine();
//5.判斷檔案是否存在,将結果發回用戶端
File dir = new File("updata");
dir.mkdir(); //建立檔案夾
File file = new File(dir,fileName); //封裝成file對象
if(file.exists()) { //如果伺服器已經勳在這個檔案
ps.println("存在"); //将存在寫給用戶端
socket.close();
return;
}else {
ps.println("不存在");
}
//8.定義fileoutputstream,從網絡讀取資料,存儲到本地
FileOutputStream fos = new FileOutputStream(file);
byte[] arr = new byte[8192];
int len;
while((len = is.read(arr)) != -1) {
fos.write(arr,0 ,len);
}
fos.close();
socket.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}