很久以前的一個Demo,這裡服務器只做轉發功能,根據ID地址和端口號來標識身份,群聊和私聊只是簡單實現,
服務器代碼如下:
import java.util.*; import java.io.*; import java.net.*; public class Server extends Thread { private static Vector<Socket> vecClient = new Vector<Socket>(); private PrintWriter out; private BufferedReader in; private Socket clientsocket; public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(2014); // 創建 System.out.println("啟動服務器! "); Socket sock; while (true) { sock = server.accept(); // 等待客戶請求 Server ser = new Server(sock); ser.start(); // 啟動 } } public Server(Socket socket) { this.clientsocket = socket; vecClient.addElement(socket); // 增加客戶線程到數組 try { // 獲取服務端傳來的字節流好,存到緩沖區 in = new BufferedReader(new InputStreamReader( socket.getInputStream())); // printwriter,文本輸出流打印對象的格式化表示形式,只有調用println等,自動刷新即true,強行把緩沖區的數據輸出。 out = new PrintWriter(new OutputStreamWriter( socket.getOutputStream()), true); // input、OutputStreamWriter 是字符流通向字節流的橋梁 } catch (IOException e) { } } public void run() { try { Newclient(); // 向新客戶發出歡迎信息,通知所有在線客戶有新客戶連接了 while(true) // 處理與客戶的交流 { String msg=in.readLine(); //數據讀取 if(msg.equals("bye")|| msg.equals("拜拜"))//當輸入拜拜或bye時候退出 { Xiaxian(); in.close(); // 關閉輸入流 clientsocket.close(); // 關閉socket break; } else if(msg.indexOf("@")==0&&msg.indexOf(" ")>0){ int end=msg.indexOf(" "); String findAddr=msg.substring(1,end); if(vecClient.isEmpty() == false) //判斷為空 { for(int i=0;i<vecClient.size();i++) { Socket socket = vecClient.get(i); String addr = socket.getInetAddress().toString().replace("/", "") + ":" + socket.getPort(); if(findAddr.equals(addr)){ String addr2 = clientsocket.getInetAddress().toString().replace("/", "") + ":" + clientsocket.getPort(); //elementAt返回指定索引處的組件,而get返回列表中指定位置處的元素 PrintWriter pw = new PrintWriter(new OutputStreamWriter(vecClient.get(i).getOutputStream()),true); pw.println("大神"+addr2+" 對你 說: "+msg.substring(end)); } } } } // 否則將接收到的信息向所有在線客戶發出去 else { if(vecClient.isEmpty() == false) for(int i=0;i<vecClient.size();i++) { //elementAt返回指定索引處的組件,而get返回列表中指定位置處的元素 PrintWriter pw = new PrintWriter(new OutputStreamWriter(vecClient.get(i).getOutputStream()),true); pw.println("大神"+clientsocket.getInetAddress().toString()+":"+clientsocket.getPort()+" 說: "+msg); } } } } catch(IOException e) { } } public void Newclient() throws IOException // 新來的,用此函數 { String addr = clientsocket.getInetAddress().toString() + ":" + clientsocket.getPort(); out.println("歡迎:" + addr+"加入! "); try { if (vecClient.isEmpty() == false) for (int i = 0; i < vecClient.size(); i++) { Socket socket = vecClient.get(i); PrintWriter pw = new PrintWriter(new OutputStreamWriter( socket.getOutputStream()), true); String addr2 = socket.getInetAddress().toString() + ":" + socket.getPort(); if (addr.equals(addr2)) { pw.println("歡迎加入聊天,私聊請用@ip:port 內容"); } else { pw.println("新成員:" + clientsocket.getInetAddress().toString() + ":" + clientsocket.getPort() + " 嗨起來吧!"); } } } catch (IOException e) { } } public void Xiaxian() throws IOException // 下線方法 { out.println("再見,連接關閉!"); if (vecClient.isEmpty() == false) for (int i = 0; i < vecClient.size(); i++) { PrintWriter pw = new PrintWriter(new OutputStreamWriter(vecClient .get(i).getOutputStream()), true); pw.println("--" + clientsocket.getInetAddress().toString() + ":" + clientsocket.getPort() + " 已經下線"); } vecClient.remove(clientsocket); } }View Code
客服端,可在本地命令運行多個測試,私聊格式:@ip:port(這裡必須有空格)內容,原理如下:
import java.net.*; import java.io.*; import java.util.*; class Client { public static void main(String[] args) { try { Socket socket=new Socket("localhost",2014); ClientSend send=new ClientSend(socket); // 創建發送線程 ClientReceive receive=new ClientReceive(socket); // 創建接收線程 send.start(); // 啟動發送線程 receive.start(); // 啟動接收線程 } catch(Exception e) { System.out.println("服務器沒有開啟呢!"); e.printStackTrace(); } } } class ClientSend extends Thread { private Socket socket; private PrintWriter out; public ClientSend(Socket socket) { this.socket=socket; try { out=new PrintWriter(new OutputStreamWriter(socket.getOutputStream()),true); //返回一個服務器與客戶端的輸出流,true強行把緩沖區的數據輸出 } catch(IOException e) { e.printStackTrace(); } } public void run() // 發送信息到服務器 { String msg; Scanner input=new Scanner(System.in);//輸入 msg = input.nextLine(); //nextLine方法返回的是回車之前的所有字符 while(true) { //用equalsIgnoreCase可忽略大小寫 if(msg.equals("bye") || msg.equals("拜拜")) { out.println(msg); break; } out.println(msg); msg = input.nextLine(); } } } class ClientReceive extends Thread //接收 { private Socket socket; private BufferedReader in; public ClientReceive(Socket socket) { this.socket= socket; try { in=new BufferedReader(new InputStreamReader(socket.getInputStream())); } catch(IOException e) { e.printStackTrace(); } } public void run() // 接收服務器發來的信息 { try { String msg=in.readLine(); while(msg.equals("bye") == false) { System.out.println(msg); msg=in.readLine(); } in.close(); socket.close(); } catch(IOException e) { e.printStackTrace(); } } }View Code