標籤:cs 伺服器 多線程 網路編程 socket
C/S聊天室分為伺服器端和用戶端,均需要採用多線程來實現。
伺服器端主線程需要不斷地監聽連接埠,一旦有用戶端的請求時,產生相應的Socket,將其加入到隊列中並啟動子線程,子線程負責接收用戶端訊息(使用Socket的getInputStream()函數來處理),再將訊息發送到所有的用戶端(使用Socket的getOutputStream()函數)。
用戶端主線程負責擷取鍵盤輸入(相當於偵聽鍵盤輸入),並傳遞給Socket的輸出資料流(使用Socket的getOutputStream(),為什麼這裡是getOutputStream(),因為對Socket而言是輸出資料流),而子線程負責取得伺服器端發過來的訊息(使用Socket的getInputStream())。
代碼如下,代碼沒有實現介面:
import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;public class Server {private final int PORT=30000;public static ArrayList<Socket> socketList=new ArrayList<Socket>();public void init(){try (ServerSocket serverSocket=new ServerSocket(PORT);){while(true){Socket socket=serverSocket.accept();socketList.add(socket);new Thread(new ServerThread(socket)).start();}}catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("伺服器啟動失敗,是否"+PORT+"連接埠已被佔用?");}}public static void main(String[] args) {// TODO Auto-generated method stubServer s=new Server();s.init();}}
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;public class ServerThread implements Runnable{private Socket s=null;private BufferedReader br=null;public ServerThread(Socket s){this.s=s;}@Overridepublic void run() {// TODO Auto-generated method stubtry {br=new BufferedReader(new InputStreamReader(s.getInputStream()));} catch (IOException e) {// TODO Auto-generated catch blockSystem.out.println("Socket對應的輸入資料流擷取失敗!");}String content=null;while((content=readFromClient())!=null){for(Socket s:Server.socketList){try (PrintStream ps=new PrintStream(s.getOutputStream()); // 讓該程式通過該輸出資料流向socket中輸出資料){ps.println(content);}catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}private String readFromClient() {// TODO Auto-generated method stubtry {return br.readLine();} catch (IOException e) {// TODO Auto-generated catch blockServer.socketList.remove(s);}return null;}}
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintStream;import java.net.Socket;import java.net.UnknownHostException;public class Client {private final static int PORT=30000;private final static String host="127.0.0.1";public static void main(String[] args) throws UnknownHostException, IOException {// TODO Auto-generated method stubSocket s=new Socket(host,PORT);new Thread(new ClientThread(s)).start(); // 子線程完成與伺服器通訊PrintStream ps=new PrintStream(s.getOutputStream()); // 讓程式通過該輸出資料流向Socket中輸出資料,得到了socket的輸出資料流String line=null;BufferedReader br=new BufferedReader(new InputStreamReader(System.in));// br.readline()不斷讀取鍵盤輸入內容while((line=br.readLine())!=null){ps.println(line);}}}
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.net.Socket;public class ClientThread implements Runnable {private Socket s=null;private BufferedReader br=null;public ClientThread(Socket s) throws IOException{this.s=s;br=new BufferedReader(new InputStreamReader(s.getInputStream())); // 該句只是返回了這樣一個對象,裡面並不包含螢幕中的語句} // 其用readline()的時候才得到輸入語句@Overridepublic void run() {// TODO Auto-generated method stubString content=null;try {while((content=br.readLine())!=null) // readline()遇到輸入末尾的時候才會返回null{System.out.println(content);}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
參考資料:瘋狂JAVA講義