在客戶/伺服器通信模式中,伺服器端需要建立監聽特定端口的ServerSocket,ServerSocket負責接收客戶連接配接請求。首先介紹ServerSocket類的各個構造方法,以及成員方法的用法,接着介紹伺服器如何用多線程來處理與多個客戶的通信任務。
ServerSocket的構造方法有以下幾種重載形式:
◆ServerSocket()throws IOException
◆ServerSocket(int port) throws IOException
◆ServerSocket(int port, int backlog) throws IOException
◆ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
在以上構造方法中,參數port指定伺服器要綁定的端口(伺服器要監聽的端口),參數backlog指定客戶連接配接請求隊列的長度,參數bindAddr指定伺服器要綁定的IP位址。
除了第一個不帶參數的構造方法以外,其他構造方法都會使伺服器與特定端口綁定,該端口由參數port指定。例如,以下代碼建立了一個與9999端口綁定的伺服器:
ServerSocket serverSocket=new ServerSocket(9999);
如果運作時無法綁定到80端口,以上代碼會抛出IOException,更确切地說,是抛出BindException,它是IOException的子類。BindException一般是由以下原因造成的:
◆端口已經被其他伺服器程序占用;
◆在某些作業系統中,如果沒有以超級使用者的身份來運作伺服器程式,那麼作業系統不允許伺服器綁定到1~1023之間的端口。0~1023之間的端口是用于綁定Binding的一些服務的端口。
如果把參數port設為0,表示由作業系統來為伺服器配置設定一個任意可用的端口。由作業系統配置設定的端口也稱為匿名端口。對于多數伺服器,會使用明确的端口,而不會使用匿名端口,因為客戶程式需要事先知道伺服器的端口,才能友善地通路伺服器。
聊天伺服器小Demo
/**
* ServerSocket簡單聊天伺服器
* @author 鐘宇峰
*/
public class ServerDemo {
private Socket socket;
private ServerSocket server;
//主函數
public static void main(String[] args) {
ServerDemo sd = new ServerDemo();
sd.createServer(9999);
}
/**
* 建立伺服器
* @param port 端口号
*/
public void createServer(int port){
try {
//建立伺服器
server = new ServerSocket(port);
System.out.println("伺服器建立成功....");
System.out.println("伺服器處于阻塞狀态中,等待客戶機連接配接.....");
//伺服器阻塞中等待客戶機連接配接
whlie(true){
socket = server.accept();
System.out.println("客戶機"+(i-1)+"連接配接成功!"+socket.getRemoteSocketAddress());
ClientDemo cd = new ClientDemo(server,socket);
cd.start();
}
//客戶機已連接配接
server.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
-----------------------------------------------------------------------------
public class ClientDemo extends Thread {
private ServerSocket server;
private Socket socket;
public ClientDemo(ServerSocket server, Socket socket) {
this.socket = socket;
this.server = server;
}
public void run() {
while (true) {
try {
OutputStream os = socket.getOutputStream();
// BufferedReader br = new BufferedReader(new
// InputStreamReader(is));
InputStream is = socket.getInputStream();
String msg = "歡迎登陸聊天室!\r\n";
os.write(msg.getBytes());
msg = "";
while (!msg.equals("exit")) {
int i = 0;
StringBuffer strb = new StringBuffer();
while ((i = is.read()) != 13) {//
// 讀取客戶機發送過來的消息,隻要不是13就繼續讀取,如果是13則結束
strb.append((char) i);
}
is.read();// 讀取換行符,丢掉
msg = strb.toString();
// msg = br.readLine();
System.out.println("客戶機說:" + msg);
os.write(("伺服器說:" + msg + "\r\n").getBytes());
}
os.close();
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
在伺服器建立中我們使用while(true){}循環確定伺服器不會停止,一直處于阻塞狀态中等待連接配接進來的客戶機。ClientDemo類繼承了線程,在run方法中建立客戶機對象,初始化IO流。這樣我們就可以生成多個用戶端進而實作聊天功能。在這個基礎上可以逐漸加深,實作群聊功能,私聊,寫自己設計的界面,制定通信協定以實作諸多功能。