Socket是指在一個特定編程模型下,處理序間通訊鏈路的端點。因為這個特定編程模型的流行,Socket這個名字在其他領域得到了複用,包括Java叫技術。
如果要建立串連,一台機器必須運行一個進程來等待串連,而另一台機器必須試圖到達第一台機器。這個電話系統類別似:一方必鬚髮起呼叫,而另一方在此時必須等待撥打電話。
java網路模型圖
下面通過一個有“回顯”功能的伺服器和用戶端來介紹應用java.net包編寫網路應用程式。
這個例子主要功能是伺服器端的程式等待客戶的輸入,然後將讀取到的資訊回顯給用戶端,同時在伺服器端的控制台輸出。而用戶端從控制台接收資訊後,向用戶端發送輸入,並接收伺服器的回顯資料,然後顯示在控制台。
用戶端程式代碼如下:
複製代碼 代碼如下:
package com.javapp.ch11;
import java.io.*;
import java.net.*;
/**
* Description: 具有“回顯”功能的伺服器端和用戶端程式
*/
public class EchoClientDemo {
// 伺服器端的服務連接埠。
public static final int SERVERPORT = 990;
public static void main(String[] args) {
try {
// 建立串連通訊端。
Socket s = new Socket("localhost",SERVERPORT);
System.out.println("socket = " + s);
// 建立網路連接的輸入資料流。
BufferedReader in = new BufferedReader(new InputStreamReader(s
.getInputStream()));
// 建立網路連接的自動重新整理的輸出資料流。
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())),true);
// 先使用System.in構造InputStreamReader,再構造BufferedReader。
BufferedReader stdin = new BufferedReader(
new InputStreamReader(System.in));
System.out.println("Enter a string, Enter BYE to exit! ");
while (true) {
// 讀取從控制台輸入的字串,並向網路連接輸出,即向伺服器端發送資料。
out.println(stdin.readLine());
// 從網路連接讀取一行,即接收伺服器端的資料。
String str = in.readLine();
// 如果接收到的資料為空白(如果直接按Enter,不是空資料),則退出迴圈,關閉串連。
if (str == null) {
break;
}
System.out.println(str);
}
s.close();
} catch (IOException e) {
System.err.println("IOException" + e.getMessage());
}
}
}
上面用戶端程式中。首先用java.net包中的Socket類建立一個串連通訊端,其後應用的Socket對象的getInputStream方法從伺服器接收資料,並且應用Socket對象的getOuputStream方法發送資料到伺服器。建立完輸入輸出資料流,就可以像讀寫檔案的方式來讀寫資料。
支援多用戶端的“回顯”伺服器端程式碼如下:
複製代碼 代碼如下:
package com.javapp.ch11;
import java.io.*;
import java.net.*;
/**
* Description:支援多用戶端的“回顯”伺服器端程式
*/
public class EchoServerThreadDemo {
// 伺服器端的服務連接埠。
public static final int SERVERPORT = 990;
public static void main(String[] args) {
try {
// 已經串連上的用戶端的序號。
int number = 1;
// 建立伺服器端傾聽通訊端。
ServerSocket s = new ServerSocket(SERVERPORT);
System.out.println("Started: " + s);
while (true) {
// 等待並接收請求,建立串連通訊端。
Socket incoming = s.accept();
System.out.println("Connection " + number + " accepted: ");
System.out.println(incoming);
// 啟動一個線程來進行伺服器端和用戶端的資料轉送。
// 主程式繼續監聽是否有請求到來。
Thread t = new EchoThread(incoming,number);
t.start();
number++;
}
} catch (IOException e) {
System.err.println("IOException");
}
}
}
class EchoThread extends Thread {
private Socket s;
int n;
public EchoThread(Socket incoming,int number) {
s = incoming;
n = number;
}
public void run() {
try {
// 建立網路連接的輸入資料流。
BufferedReader in = new BufferedReader(new InputStreamReader(s
.getInputStream()));
// 建立網路連接的自動重新整理的輸出資料流。
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(s.getOutputStream())),true);
System.out.println("Hello! Enter BYE to exit.");
// 回顯用戶端的輸入。
while (true) {
// 從網路連接讀取一行,即接收用戶端的資料。
String line = in.readLine();
// 如果接收到的資料為空白(如果直接按Enter,不是空資料),則退出迴圈,關閉串連。
if (line == null) {
break;
} else {
if (line.trim().equals("BYE")) {
System.out.println("The client " + n + " entered BYE!");
System.out.println("Connection " + n + " will be closed!");
break;
}
System.out.println("Echo " + n + ": " + line);
// 向網路連接輸出一行,即向用戶端發送資料。
out.println("Echo " + n + ": " + line);
}
}
// 關閉通訊端。
s.close();
} catch (IOException e) {
System.err.println("IOException");
}
}
}
在伺服器端程式中,首先用java.net包中的ServerSocket類建立一個伺服器端偵聽通訊端。其後應用ServerSocket類的accept方法等待並接收使用者請求。當伺服器每接收到一個串連請求後,就啟動一個線程來單獨處理伺服器和用戶端的資料轉送。伺服器端資料的接收和發送與上面介紹的用戶端資料的發送和介紹相同。