網絡編程的本質是兩台計算機之間的數據通訊。對開發者而言,掌握一套編程接口與模型即可輕鬆實現。Java SDK在java.net包中提供了豐富的API,其中Socket是核心組件之一,只需導入該包即可開展網絡開發。
網絡編程的基礎模型是客戶端-服務器架構:兩個進程通訊,一方提供固定位置(服務器),另一方主動連接(客戶端)。Java通過ServerSocket支持服務端,創建實例並綁定端口即可建立監聽點:
ServerSocket server = new ServerSocket(6789);
注意:端口號範圍0-65535,前1024為系統保留,自定義服務需使用1024以上端口,且必須唯一。
客戶端使用Socket發起連接,需知服務器IP地址。Java提供InetAddress類獲取地址信息:
Socket client = new Socket(InetAddress.getLocalHost(), 5678);
網絡通訊本質是I/O操作。通過Socket的getInputStream()和getOutputStream()獲取流,再配合BufferedReader、PrintWriter處理文本:
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(socket.getOutputStream());
public class MyServer {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(5678);
Socket client = server.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());
while (true) {
String str = in.readLine();
System.out.println(str);
out.println("has receive....");
out.flush();
if ("end".equals(str)) break;
}
client.close();
}
}
public class Client {
public static void main(String[] args) throws Exception {
Socket server = new Socket(InetAddress.getLocalHost(), 5678);
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
PrintWriter out = new PrintWriter(server.getOutputStream());
BufferedReader wt = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String str = wt.readLine();
out.println(str);
out.flush();
if ("end".equals(str)) break;
System.out.println(in.readLine());
}
server.close();
}
}
單線程模型下,服務端僅能串行處理請求。引入while(true)外層循環可接受多個連接,但仍屬串行。真正的併發需引入多線程:
public class MultiUser extends Thread {
private Socket client;
public MultiUser(Socket c) { this.client = c; }
public void run() {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream());
while (true) {
String str = in.readLine();
System.out.println(str);
out.println("has receive....");
out.flush();
if ("end".equals(str)) break;
}
client.close();
} catch (IOException ex) { }
}
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(5678);
while (true) {
MultiUser mu = new MultiUser(server.accept());
mu.start();
}
}
}
每個客戶端連接獨立線程處理,實現真正併發。主線程循環accept(),將Socket傳遞給工作線程,各線程獨享通訊通道,互不干擾。