這篇文章主要介紹Java編程Socket如何實(shí)現(xiàn)多個(gè)客戶端連接同一個(gè)服務(wù)端,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
創(chuàng)新互聯(lián)總部坐落于成都市區(qū),致力網(wǎng)站建設(shè)服務(wù)有成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)、網(wǎng)絡(luò)營(yíng)銷策劃、網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站維護(hù)、公眾號(hào)搭建、成都小程序開發(fā)、軟件開發(fā)等為企業(yè)提供一整套的信息化建設(shè)解決方案。創(chuàng)造真正意義上的網(wǎng)站建設(shè),為互聯(lián)網(wǎng)品牌在互動(dòng)行銷領(lǐng)域創(chuàng)造價(jià)值而不懈努力!
Java Socket(套接字)通常也稱作"套接字",用于描述IP地址和端口,是一個(gè)通信鏈的句柄。應(yīng)用程序通常通過(guò)"套接字"向網(wǎng)絡(luò)發(fā)出請(qǐng)求或者應(yīng)答網(wǎng)絡(luò)請(qǐng)求。
使用Socket實(shí)現(xiàn)多個(gè)客戶端和同一客戶端通訊;首先客戶端連接服務(wù)端發(fā)送一條消息,服務(wù)端接收到消息后進(jìn)行處理,完成后再回復(fù)客戶端一條消息。本人通過(guò)自己的思維編寫了一份服務(wù)端和客戶端實(shí)現(xiàn)的代碼,望能與大家相互學(xué)習(xí),共同進(jìn)步。
服務(wù)端代碼
/** * Socket服務(wù)端 * 功能說(shuō)明: * */ public class Server { /** * 入口 * * @param args * @throws IOException */ public static void main(String[] args) throws IOException { // 為了簡(jiǎn)單起見,所有的異常信息都往外拋 int port = 8899; // 定義一個(gè)ServiceSocket監(jiān)聽在端口8899上 ServerSocket server = new ServerSocket(port); System.out.println("等待與客戶端建立連接..."); while (true) { // server嘗試接收其他Socket的連接請(qǐng)求,server的accept方法是阻塞式的 Socket socket = server.accept(); /** * 我們的服務(wù)端處理客戶端的連接請(qǐng)求是同步進(jìn)行的, 每次接收到來(lái)自客戶端的連接請(qǐng)求后, * 都要先跟當(dāng)前的客戶端通信完之后才能再處理下一個(gè)連接請(qǐng)求。 這在并發(fā)比較多的情況下會(huì)嚴(yán)重影響程序的性能, * 為此,我們可以把它改為如下這種異步處理與客戶端通信的方式 */ // 每接收到一個(gè)Socket就建立一個(gè)新的線程來(lái)處理它 new Thread(new Task(socket)).start(); } // server.close(); } /** * 處理Socket請(qǐng)求的線程類 */ static class Task implements Runnable { private Socket socket; /** * 構(gòu)造函數(shù) */ public Task(Socket socket) { this.socket = socket; } @Override public void run() { try { handlerSocket(); } catch (Exception e) { e.printStackTrace(); } } /** * 跟客戶端Socket進(jìn)行通信 * * @throws IOException */ private void handlerSocket() throws Exception { // 跟客戶端建立好連接之后,我們就可以獲取socket的InputStream,并從中讀取客戶端發(fā)過(guò)來(lái)的信息了 /** * 在從Socket的InputStream中接收數(shù)據(jù)時(shí),像上面那樣一點(diǎn)點(diǎn)的讀就太復(fù)雜了, * 有時(shí)候我們就會(huì)換成使用BufferedReader來(lái)一次讀一行 * * BufferedReader的readLine方法是一次讀一行的,這個(gè)方法是阻塞的,直到它讀到了一行數(shù)據(jù)為止程序才會(huì)繼續(xù)往下執(zhí)行, * 那么readLine什么時(shí)候才會(huì)讀到一行呢?直到程序遇到了換行符或者是對(duì)應(yīng)流的結(jié)束符readLine方法才會(huì)認(rèn)為讀到了一行, * 才會(huì)結(jié)束其阻塞,讓程序繼續(xù)往下執(zhí)行。 * 所以我們?cè)谑褂肂ufferedReader的readLine讀取數(shù)據(jù)的時(shí)候一定要記得在對(duì)應(yīng)的輸出流里面一定要寫入換行符( * 流結(jié)束之后會(huì)自動(dòng)標(biāo)記為結(jié)束,readLine可以識(shí)別),寫入換行符之后一定記得如果輸出流不是馬上關(guān)閉的情況下記得flush一下, * 這樣數(shù)據(jù)才會(huì)真正的從緩沖區(qū)里面寫入。 */ 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時(shí)就結(jié)束接收 sb.append(temp.substring(0, index)); break; } sb.append(temp); } System.out.println("Form Cliect[port:" + socket.getPort() + "] 消息內(nèi)容:" + sb.toString()); // 回應(yīng)一下客戶端 Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8"); writer.write(String.format("Hi,%d.天朗氣清,惠風(fēng)和暢!", socket.getPort())); writer.flush(); writer.close(); System.out.println( "To Cliect[port:" + socket.getPort() + "] 回復(fù)客戶端的消息發(fā)送成功"); br.close(); socket.close(); } } }
客戶端代碼
import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.net.Socket; /** * Socket客戶端 * 功能說(shuō)明: * * @author 大智若愚的小懂 * @Date 2016年8月30日 * @version 1.0 */ public class Client { /** * 入口 * @param args */ public static void main(String[] args) { // 開啟三個(gè)客戶端,一個(gè)線程代表一個(gè)客戶端 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(); } } /** * 生產(chǎn)測(cè)試客戶端的工廠 */ static class TestClientFactory { public static TestClient createClient() throws Exception { return new TestClient("127.0.0.1", 8899); } } /** * 測(cè)試客戶端 */ static class TestClient { /** * 構(gòu)造函數(shù) * @param host 要連接的服務(wù)端IP地址 * @param port 要連接的服務(wù)端對(duì)應(yīng)的監(jiān)聽端口 * @throws Exception */ public TestClient(String host, int port) throws Exception { // 與服務(wù)端建立連接 this.client = new Socket(host, port); System.out.println("Cliect[port:" + client.getLocalPort() + "] 與服務(wù)端建立連接..."); } private Socket client; private Writer writer; /** * 發(fā)送消息 * @param msg * @throws Exception */ public void send(String msg) throws Exception { // 建立連接后就可以往服務(wù)端寫數(shù)據(jù)了 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() + "] 消息發(fā)送成功"); } /** * 接收消息 * @throws Exception */ public void receive() throws Exception { // 寫完以后進(jìn)行讀操作 Reader reader = new InputStreamReader(client.getInputStream(), "UTF-8"); // 設(shè)置接收數(shù)據(jù)超時(shí)間為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() + "] 消息收到了,內(nèi)容:" + sb.toString()); reader.close(); // 關(guān)閉連接 writer.close(); client.close(); } } }
接下來(lái)模擬一下:
1.首先運(yùn)行服務(wù)端
2.接著運(yùn)行客戶端(開三個(gè)客戶端請(qǐng)求)
為了演示有所區(qū)分,服務(wù)端我使用的是Eclipse工具,客戶端使用的是IntelliJ IDEA工具。這時(shí)可以看到客戶端在控制臺(tái)打印出來(lái)的消息
一個(gè)Port端口號(hào)代表一個(gè)客戶端,回過(guò)來(lái)看下服務(wù)端在控制臺(tái)打印出來(lái)的消息
以上是“Java編程Socket如何實(shí)現(xiàn)多個(gè)客戶端連接同一個(gè)服務(wù)端”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!