用Java實現多線程ServerSocket伺服器程式

來源:互聯網
上載者:User
 

Java是伴隨Internet的大潮產生的,對網路及多線程具有內在的支援,具有網路時代程式設計語言的一切特點。從Java的當前應用看,Java
主要用於在Internet或區域網路上的網路編程,而且將Java作為主流的網路程式設計語言的趨勢愈來愈明顯。實際工作中,我們除了使用商品化的伺服器軟體
外,時常需要按照實際環境編寫自己的伺服器軟體,以完成特定任務或與特定用戶端軟體實現互動。在實現伺服器程式時,為提高程式運行效率,降低使用者等待時
間,我們應用了在Java Applet中常見的多線程技術。

一、Java中的伺服器程式與多線程

在Java之前,沒有一種主流程式設計語言能夠提供對進階網路編程的固有支援。在其他語言環境中,實現網路程式往往需要深入依賴於操作平台的網路API的技術中去,而Java提供了對網路支援的無平台相關性的完整軟體包,使程式員沒有必要為系統網路支援的細節而煩惱。

Java軟體包內在支援的網路通訊協定為TCP/IP,也是當今最流行的廣域網路/區域網路協議。Java有關網路的類及介面定義在java.net包中。
用戶端軟體通常使用java.net包中的核心類Socket與伺服器的某個連接埠建立串連,而伺服器程式不同於客戶機,它需要初始化一個連接埠進行監聽,遇
到串連呼叫,才與相應的客戶機建立串連。Java.net包的ServerSocket類包含了編寫伺服器系統所需的一切。下面給出
ServerSocket類的部分定義。

public class ServerSocket { 
public ServerSocket(int port)
throws IOException ;
public Socket accept() throws IOException ;
public InetAddress getInetAddress() ;
public int getLocalPort() ;
public void close() throws IOException ;
public synchronized void setSoTimeout
(int timeout) throws SocketException ;
public synchronized int
getSoTimeout() throws IOException ;

ServerSocket構造器是伺服器程式啟動並執行基礎,它將參數port指定的連接埠初始化作為該伺服器的連接埠,監聽客戶機串連請求。Port的範
圍是0到65536,但0到1023是標準Internet協議保留連接埠,而且在Unix主機上,這些連接埠只有root使用者可以使用。一般自訂的連接埠號碼
在8000到16000之間。僅初始化了ServerSocket還是遠遠不夠的,它沒有同客戶機互動的通訊端(Socket),因此需要調用該類的
accept方法接受客戶呼叫。Accept()方法直到有串連請求才返回通訊通訊端(Socket)的執行個體。通過這個執行個體的輸入、輸出資料流,伺服器可以接
收使用者指令,並將相應結果回應客戶機。ServerSocket類的getInetAddress和getLocalPort方法可得到該伺服器的IP地
址和連接埠。setSoTimeout和getSoTimeout方法分別是設定和得到伺服器逾時設定,如果伺服器在timout設定時間內還未得到
accept方法返回的通訊端執行個體,則拋出IOException的異常。

Java的多線程可謂是Java編程的精華之一,運用得當可以極大地改善程式的回應時間,提高程式的並行性。在伺服器程式中,由於往往要接收不同客
戶機的同時請求或命令,因此可以對每個客戶機的請求產生一個命令處理線程,同時對各使用者的指令作出反應。在一些較複雜的系統中,我們還可以為每個資料庫查
詢指令產生單獨的線程,並行對資料庫進行操作。實踐證明,採用多線程設計可以很好的改善系統的響應,並保證使用者指令執行的獨立性。由於Java本身是“線
程安全”的,因此有一條編程原則是能夠獨立在一個線程中完成的操作就應該開闢一個新的線程。

Java中實現線程的方式有兩種,一是產生Thread類的子類,並定義該子類自己的run方法,線程的操作在方法run中實現。但我們定義的類一
般是其他類的子類,而Java又不允許多重繼承,因此,第二種實現線程的方法是實現Runnable介面。通過覆蓋Runnable介面中的run方法實
現該線程的功能。本文例子採用第一種方法實現線程。

二、多線程伺服器程式舉例

以下是我們在項目中採用的多線程伺服器程式的架構,可以在此基礎上對命令進行擴充。本例未涉及資料庫。如果線上程運行中需要根據使用者指令對資料庫進
行更新操作,則應注意線程間的同步問題,使同一更新方法一次只能由一個線程調用。這裡我們有兩個類,receiveServer包含啟動代碼(main
()),並初始化ServerSocket的執行個體,在accept方法返回使用者請求後,將返回的通訊端(Socket)交給產生的線程類
serverThread的執行個體,直到該使用者結束串連。

//類receiveServer 
import java.io.*;
import java.util.*;
import java.net.*;
public class receiveServer{
final int RECEIVE_PORT=9090;
//該伺服器的連接埠號碼
//receiveServer的構造器
public receiveServer() {
ServerSocket rServer=null;
//ServerSocket的執行個體
Socket request=null; //使用者請求的通訊端
Thread receiveThread=null;
try{
rServer=new ServerSocket(RECEIVE_PORT);
//初始化ServerSocket
System.out.println("Welcome to the server!");
System.out.println(new Date());
System.out.println("The server is ready!");
System.out.println("Port: "+RECEIVE_PORT);
while(true){ //等待使用者請求
request=rServer.accept();
//接收客戶機串連請求
receiveThread=new serverThread(request);
//產生serverThread的執行個體
receiveThread.start();
//啟動serverThread線程
}
}catch(IOException e){
System.out.println(e.getMessage());}
}
public static void main(String args[]){
new receiveServer();
} //end of main
} //end of class
//類serverThread
import java.io.*;
import java.net.*;
class serverThread extends Thread {
Socket clientRequest;
//使用者串連的通訊通訊端
BufferedReader input; //輸入資料流
PrintWriter output; //輸出資料流
public serverThread(Socket s)
{ //serverThread的構造器
this.clientRequest=s;
//接收receiveServer傳來的通訊端
InputStreamReader reader;
OutputStreamWriter writer;
try{ //初始化輸入、輸出資料流
reader=new InputStreamReader
(clientRequest.getInputStream());
writer=new OutputStreamWriter
(clientRequest.getOutputStream());
input=new BufferedReader(reader);
output=new PrintWriter(writer,true);
}catch(IOException e){
System.out.println(e.getMessage());}
output.println("Welcome to the server!");
//客戶機串連歡迎詞
output.println("Now is:
"+new java.util.Date()+" "+
"Port:"+clientRequest.getLocalPort());
output.println("What can I do for you?");
}
public void run(){ //線程的執行方法
String command=null; //使用者指令
String str=null;
boolean done=false;
while(!done){
try{
str=input.readLine(); //接收客戶機指令
}catch(IOException e){
System.out.println(e.getMessage());}
command=str.trim().toUpperCase();
if(str==null || command.equals("QUIT"))
//命令quit結束本次串連
done=true;
else if(command.equals("HELP")){
//命令help查詢本伺服器可接受的命令
output.println("query");
output.println("quit");
output.println("help");
}
else if(command.startsWith("QUERY"))
{ //命令query
output.println("OK to query something!");
}
//else if …….. //在此可加入伺服器的其他指令
else if(!command.startsWith("HELP") &&
!command.startsWith("QUIT") &&
!command.startsWith("QUERY")){
output.println("Command not Found!
Please refer to the HELP!");
}
}//end of while
try{
clientRequest.close(); //關閉通訊端
}catch(IOException e){
System.out.println(e.getMessage());
}
command=null;
}//end of run 

啟動該伺服器程式後,可用telnet machine port命令串連,其中machine為本機名或地址,port為程式中指定的連接埠。也可以編寫特定的客戶機軟體通過TCP的Socket通訊端建立串連。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.