Java Socket實現多個客戶端連線同一個服務端
阿新 • • 發佈:2019-01-03
使用Socket實現多個客戶端和同一客戶端通訊;首先客戶端連線服務端傳送一條訊息,服務端接收到訊息後進行處理,完成後再回復客戶端一條訊息。本人通過自己的思維編寫了一份服務端和客戶端實現的程式碼,望能與大家相互學習,共同進步。
服務端程式碼
客戶端程式碼/** * Socket服務端<br> * 功能說明: * * @author 大智若愚的小懂 * @Date 2016年8月30日 * @version 1.0 */ public class Server { /** * 入口 * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // 為了簡單起見,所有的異常資訊都往外拋 int port = 8899; // 定義一個ServiceSocket監聽在埠8899上 ServerSocket server = new ServerSocket(port); System.out.println("等待與客戶端建立連線..."); while (true) { // server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的 Socket socket = server.accept(); /** * 我們的服務端處理客戶端的連線請求是同步進行的, 每次接收到來自客戶端的連線請求後, * 都要先跟當前的客戶端通訊完之後才能再處理下一個連線請求。 這在併發比較多的情況下會嚴重影響程式的效能, * 為此,我們可以把它改為如下這種非同步處理與客戶端通訊的方式 */ // 每接收到一個Socket就建立一個新的執行緒來處理它 new Thread(new Task(socket)).start(); } // server.close(); } /** * 處理Socket請求的執行緒類 */ static class Task implements Runnable { private Socket socket; /** * 建構函式 */ public Task(Socket socket) { this.socket = socket; } @Override public void run() { try { handlerSocket(); } catch (Exception e) { e.printStackTrace(); } } /** * 跟客戶端Socket進行通訊 * * @throws IOException */ private void handlerSocket() throws Exception { // 跟客戶端建立好連線之後,我們就可以獲取socket的InputStream,並從中讀取客戶端發過來的資訊了 /** * 在從Socket的InputStream中接收資料時,像上面那樣一點點的讀就太複雜了, * 有時候我們就會換成使用BufferedReader來一次讀一行 * * BufferedReader的readLine方法是一次讀一行的,這個方法是阻塞的,直到它讀到了一行資料為止程式才會繼續往下執行, * 那麼readLine什麼時候才會讀到一行呢?直到程式遇到了換行符或者是對應流的結束符readLine方法才會認為讀到了一行, * 才會結束其阻塞,讓程式繼續往下執行。 * 所以我們在使用BufferedReader的readLine讀取資料的時候一定要記得在對應的輸出流裡面一定要寫入換行符( * 流結束之後會自動標記為結束,readLine可以識別),寫入換行符之後一定記得如果輸出流不是馬上關閉的情況下記得flush一下, * 這樣資料才會真正的從緩衝區裡面寫入。 */ BufferedReader br = new BufferedReader( new InputStreamReader(socket.getInputStream(), "UTF-8")); StringBuilder sb = new StringBuilder(); String temp; int index; while ((temp = br.readLine()) != null) { if ((index = temp.indexOf("eof")) != -1) { // 遇到eof時就結束接收 sb.append(temp.substring(0, index)); break; } sb.append(temp); } System.out.println("Form Cliect[port:" + socket.getPort() + "] 訊息內容:" + sb.toString()); // 迴應一下客戶端 Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8"); writer.write(String.format("Hi,%d.天朗氣清,惠風和暢!", socket.getPort())); writer.flush(); writer.close(); System.out.println( "To Cliect[port:" + socket.getPort() + "] 回覆客戶端的訊息傳送成功"); br.close(); socket.close(); } } }
<pre name="code" class="java">import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.Socket; /** * Socket客戶端<br> * 功能說明: * * @author 大智若愚的小懂 * @Date 2016年8月30日 * @version 1.0 */ public class Client { /** * 入口 * @param args */ public static void main(String[] args) { // 開啟三個客戶端,一個執行緒代表一個客戶端 for (int i = 0; i < 3; i++) { new Thread(new Runnable() { @Override public void run() { try { TestClient client = TestClientFactory.createClient(); client.send(String.format("Hello,Server!I'm %d.這週末天氣如何。", client.client.getLocalPort())); client.receive(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } } /** * 生產測試客戶端的工廠 */ static class TestClientFactory { public static TestClient createClient() throws Exception { return new TestClient("127.0.0.1", 8899); } } /** * 測試客戶端 */ static class TestClient { /** * 建構函式 * @param host 要連線的服務端IP地址 * @param port 要連線的服務端對應的監聽埠 * @throws Exception */ public TestClient(String host, int port) throws Exception { // 與服務端建立連線 this.client = new Socket(host, port); System.out.println("Cliect[port:" + client.getLocalPort() + "] 與服務端建立連線..."); } private Socket client; private Writer writer; /** * 傳送訊息 * @param msg * @throws Exception */ public void send(String msg) throws Exception { // 建立連線後就可以往服務端寫資料了 if(writer == null) { writer = new OutputStreamWriter(client.getOutputStream(), "UTF-8"); } writer.write(msg); writer.write("eof\n"); writer.flush();// 寫完後要記得flush System.out.println("Cliect[port:" + client.getLocalPort() + "] 訊息傳送成功"); } /** * 接收訊息 * @throws Exception */ public void receive() throws Exception { // 寫完以後進行讀操作 Reader reader = new InputStreamReader(client.getInputStream(), "UTF-8"); // 設定接收資料超時間為10秒 client.setSoTimeout(10*1000); char[] chars = new char[64]; int len; StringBuilder sb = new StringBuilder(); while ((len = reader.read(chars)) != -1) { sb.append(new String(chars, 0, len)); } System.out.println("Cliect[port:" + client.getLocalPort() + "] 訊息收到了,內容:" + sb.toString()); reader.close(); // 關閉連線 writer.close(); client.close(); } } }
接下來模擬一下:
1.首先執行服務端
為了演示有所區分,服務端我使用的是Eclipse工具,客戶端使用的是IntelliJ IDEA工具。這時可以看到客戶端在控制檯打印出來的訊息
一個Port埠號代表一個客戶端,回過來看下服務端在控制檯打印出來的訊息