使用 Java 進行網絡編程時,由虛擬機實現了底層複雜的網絡協議,Java 程序只需要調用 Java 標準庫提供的接口,就可以簡單高效地編寫網絡程序。Java 提供的這些標準庫存在於 java.net 包下。
TCP 編程
Socket 是一個抽象概念,一個應用程序通過一個 Socket 來建立一個遠程連接,而 Socket 內部通過 TCP/IP 協議把數據傳輸到網絡。Socket、TCP 和部分 IP 的功能都是由操作系統提供的,不同的編程語言只是提供了對操作系統調用的簡單的封裝。
服務端
public class Server {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
OutputStream output = null;
try {
serverSocket = new ServerSocket(8888);
System.out.println("Server is running...");
// 沒連接就會阻塞
socket = serverSocket.accept();
output = socket.getOutputStream();
output.write("您好,歡迎訪問服務端!".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally { //由下向上,依次關閉
if(output != null ){
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null ){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(serverSocket != null ){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
結果:Server is running...
客戶端
public class Client {
public static void main(String[] args) {
Socket socket = null;
InputStream input = null;
try {
InetAddress addressIP = InetAddress.getByName("127.0.0.1");
int port = 8888;
socket = new Socket(addressIP, port); //嘗試建立連接
input = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
StringBuilder sb = new StringBuilder();
while ((len = input.read(bytes)) != -1) {
sb.append(new String(bytes, 0, len, "UTF-8"));
}
System.out.println(sb);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(input != null ){
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket != null ){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
結果:您好,歡迎訪問服務端!
UDP 編程
UDP編程就簡單得多,因爲UDP沒有創建連接,數據包也是一次收發一個,所以沒有流的概念。
服務端
public class Server {
public static void main(String[] args) {
DatagramSocket ds = null;
try {
ds = new DatagramSocket(6666); // 監聽指定端口
for (;;) {
// 數據緩衝區:
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
ds.receive(packet); // 收取一個UDP數據包
String s = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8);
System.out.println(s);
// 發送數據:
byte[] data = "請求已收到!".getBytes(StandardCharsets.UTF_8);
packet.setData(data);
ds.send(packet);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
ds.close();
}
}
}
結果:你好,我發了個包!
客戶端
public class Client {
public static void main(String[] args) {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
ds.setSoTimeout(1000);
ds.connect(InetAddress.getByName("localhost"), 6666);
// 發送:
byte[] data = "你好,我發了個包!".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length);
ds.send(packet);
// 接收:
byte[] buffer = new byte[1024];
packet = new DatagramPacket(buffer, buffer.length);
ds.receive(packet);
String resp = new String(packet.getData(), packet.getOffset(), packet.getLength());
System.out.println(resp);
ds.disconnect();
} catch (Exception e) {
e.printStackTrace();
} finally {
ds.close();
}
}
}
結果:請求已收到!
HTTP 編程
HTTP 是 HyperText Transfer Protocol 的縮寫,翻譯爲超文本傳輸協議,它是基於 TCP 協議之上的一種請求-響應協議。HTTP 請求的格式是固定的,它由 HTTP Header 和 HTTP Body 兩部分構成。
服務端
服務器端的 HTTP 編程本質上就是編寫 Web 服務器,這是一個非常複雜的體系,也是 JavaEE 開發的核心內容,本次就不實現了。
客戶端
瀏覽器也是一種 HTTP 客戶端,客戶端的 HTTP 編程,它的行爲本質上和瀏覽器是一樣的,即發送一個 HTTP 請求,接收服務器響應後,獲得響應內容。
public class Client {
public static void main(String[] args) throws IOException {
URL url = new URL("https://www.baidu.com/");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setUseCaches(false);
conn.setConnectTimeout(5000); // 請求超時5秒
// 設置HTTP頭:
conn.setRequestProperty("Accept", "*/*");
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 11; Windows NT 5.1)");
// 連接併發送HTTP請求:
conn.connect();
// 判斷HTTP響應是否200:
if (conn.getResponseCode() != 200) {
throw new RuntimeException("bad response");
}
// 獲取所有響應Header:
Map<String, List<String>> map = conn.getHeaderFields();
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
// 獲取響應內容:
InputStream input = conn.getInputStream();
}
}
從 Java 11 開始,引入了新的 HttpClient,它使用鏈式調用的 API,能大大簡化 HTTP 的處理。