由於SSClient使用了流套接字所以服務程序也要使用流套接字
這就要創建一個ServerSocket對象ServerSocket有幾個構造函數最簡單的是ServerSocket(int port)當使用ServerSocket(int port)創建一個ServerSocket對象port參數傳遞端口號這個端口就是服務器監聽連接請求的端口如果在這時出現錯誤將拋出IOException異常對象否則將創建ServerSocket對象並開始准備接收連接請求
接下來服務程序進入無限循環之中無限循環從調用ServerSocket的accept()方法開始在調用開始後accept()方法將導致調用線程阻塞直到連接建立在建立連接後accept()返回一個最近創建的Socket對象該Socket對象綁定了客戶程序的IP地址或端口號
由於存在單個服務程序與多個客戶程序通訊的可能所以服務程序響應客戶程序不應該花很多時間否則客戶程序在得到服務前有可能花很多時間來等待通訊的建立然而服務程序和客戶程序的會話有可能是很長的(這與電話類似)因此為加快對客戶程序連接請求的響應典型的方法是服務器主機運行一個後台線程這個後台線程處理服務程序和客戶程序的通訊
為了示范我們在上面談到的慨念並完成SSClient程序下面我們創建一個SSServer程序程序將創建一個ServerSocket對象來監聽端口的連接請求如果成功服務程序將等待連接輸入開始一個線程處理連接並響應來自客戶程序的命令下面就是這段程序的代碼
Listing : SSServerjava
// SSServerjava
import javaio*;
import *;
import javautil*;
class SSServer
{
public static void main (String [] args) throws IOException
{
Systemoutprintln (Server starting\n);
// Create a server socket that listens for incoming connection
// requests on port
ServerSocket server = new ServerSocket ();
while (true)
{
// Listen for incoming connection requests from client
// programs establish a connection and return a Socket
// object that redivsents this connection
Socket s = serveraccept ();
Systemoutprintln (Accepting Connection\n);
// Start a thread to handle the connection
new ServerThread (s)start ();
}
}
}
class ServerThread extends Thread
{
private Socket s;
ServerThread (Socket s)
{
thiss = s;
}
public void run ()
{
BufferedReader br = null;
PrintWriter pw = null;
try
{
// Create an input stream reader that chains to the sockets
// byteoriented input stream The input stream reader
// converts bytes read from the socket to characters The
// conversion is based on the platforms default character
// set
InputStreamReader isr;
isr = new InputStreamReader (sgetInputStream ());
// Create a buffered reader that chains to the input stream
// reader The buffered reader supplies a convenient method
// for reading entire lines of text
br = new BufferedReader (isr);
// Create a print writer that chains to the sockets byte
// oriented output stream The print writer creates an
// intermediate output stream writer that converts
// characters sent to the socket to bytes The conversion
// is based on the platforms default character set
pw = new PrintWriter (sgetOutputStream () true);
// Create a calendar that makes it possible to obtain date
// and time information
Calendar c = CalendargetInstance ();
// Because the client program may send multiple commands a
// loop is required Keep looping until the client either
// explicitly requests termination by sending a command
// beginning with letters BYE or implicitly requests
// termination by closing its output stream
do
{
// Obtain the client programs next command
String cmd = brreadLine ();
// Exit if client program has closed its output stream
if (cmd == null)
break;
// Convert command to uppercase for ease of comparison
cmd = cmdtoUpperCase ();
// If client program sends BYE command terminate
if (cmdstartsWith (BYE))
break;
// If client program sends DATE or TIME command return
// current date/time to the client program
if (cmdstartsWith (DATE) || cmdstartsWith (TIME))
pwprintln (cgetTime ()toString ());
// If client program sends DOM (Day Of Month) command
// return current day of month to the client program
if (cmdstartsWith (DOM))
pwprintln ( + cget (CalendarDAY_OF_MONTH));
// If client program sends DOW (Day Of Week) command
// return current weekday (as a string) to the client
// program
if (cmdstartsWith (DOW))
switch (cget (CalendarDAY_OF_WEEK))
{
case CalendarSUNDAY : pwprintln (SUNDAY);
break;
case CalendarMONDAY : pwprintln (MONDAY);
break;
case CalendarTUESDAY : pwprintln (TUESDAY);
break;
case CalendarWEDNESDAY: pwprintln (WEDNESDAY);
break;
case CalendarTHURSDAY : pwprintln (THURSDAY);
break;
case CalendarFRIDAY : pwprintln (FRIDAY);
break;
case CalendarSATURDAY : pwprintln (SATURDAY);
}
// If client program sends DOY (Day of Year) command
// return current day of year to the client program
if (cmdstartsWith (DOY))
pwprintln ( + cget (CalendarDAY_OF_YEAR));
// If client program sends PAUSE command sleep for three
// seconds
if (cmdstartsWith (PAUSE))
try
{
Threadsleep ();
}
catch (InterruptedException e)
{
}
}
while (true);
{
catch (IOException e)
{
Systemoutprintln (etoString ());
}
finally
{
Systemoutprintln (Closing Connection\n);
try
{
if (br != null)
brclose ();
if (pw != null)
pwclose ();
if (s != null)
sclose ();
}
catch (IOException e)
{
}
}
}
}
運行這段程序將得到下面的輸出
Server starting
Accepting Connection
Closing Connection
SSServer的源代碼聲明了一對類SSServer 和ServerThreadSSServer的main()方法創建了一個ServerSocket對象來監聽端口上的連接請求如果成功 SSServer進入一個無限循環中交替調用ServerSocket的 accept() 方法來等待連接請求同時啟動後台線程處理連接(accept()返回的請求)線程由ServerThread繼承的start()方法開始並執行ServerThread的run()方法中的代碼
一旦run()方法運行線程將創建BufferedReader PrintWriter和 Calendar對象並進入一個循環這個循環由讀(通過BufferedReader的 readLine())來自客戶程序的一行文本開始文本(命令)存儲在cmd引用的string對象中如果客戶程序過早的關閉輸出流會發生什麼呢?答案是cmd將得不到賦值
注意必須考慮到這種情況在服務程序正在讀輸入流時客戶程序關閉了輸出流如果沒有對這種情況進行處理那麼程序將產生異常
一旦編譯了SSServer的源代碼通過輸入Java SSServer來運行程序在開始運行SSServer後就可以運行一個或多個SSClient程序
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25905.html