先來看一段單線程的原始代碼(代碼中有詳細(xì)的注釋):
服務(wù)器(TCPServer.java):
import java.net.*; import java.io.*; public class TCPServer{ public static void main(String[] args) throws Exception{ ServerSocket ss = new ServerSocket(5566); //創(chuàng)建一個Socket服務(wù)器,監(jiān)聽5566端口 int i=0; //利用死循環(huán)不停的監(jiān)聽端口 while(true){ Socket s = ss.accept(); //利用Socket服務(wù)器的accept()方法獲取客戶端Socket對象。 i++; System.out.println("第" + i +"個客戶端成功連接!"); DataInputStream dis = new DataInputStream(s.getInputStream()); //獲取客戶端Socket對象的輸入流,并在外邊加一層DataInputStream管道,目的是方便讀取數(shù)據(jù) System.out.println(dis.readUTF()); //讀出流中的數(shù)據(jù),DataInputStream對象的readUTF()方法可以讀出流中的數(shù)據(jù),而且支持中文 dis.close(); //關(guān)閉管道連接 s.close(); //關(guān)閉Socket連接 } } }
客戶端(TCPClient.java):
import java.net.*; import java.io.*; public class TCPClient{ public static void main(String[] args) throws Exception{ Socket s = new Socket("192.168.24.177",5566); //創(chuàng)建一個Socket對象,連接IP地址為192.168.24.177的服務(wù)器的5566端口 DataOutputStream dos = new DataOutputStream(s.getOutputStream()); //獲取Socket對象的輸出流,并且在外邊包一層DataOutputStream管道,方便輸出數(shù)據(jù) dos.writeUTF("客戶端消息"); //DataOutputStream對象的writeUTF()方法可以輸出數(shù)據(jù),并且支持中文 dos.flush(); //確保所有數(shù)據(jù)都已經(jīng)輸出 dos.close(); //關(guān)閉輸出流 s.close(); //關(guān)閉Socket連接 } }
以上代碼利用Socket對象和ServerSocket對象進(jìn)行簡單的網(wǎng)絡(luò)交互,即客戶端通過DataOutputStream對象的writeUTF()方法向服務(wù)器發(fā)送消息,服務(wù)器利用DataInputStream對象的readUTF()方法讀出數(shù)據(jù)。
看上去挺好,但ServerSocket對象的accept()方法是阻塞的方法,它會一直等待,直到有客戶端連接。
同理,DataInputStream對象的readUTF()方法也是阻塞的方法,它也會一直等待,直到客戶端調(diào)用writeUTF()方法。
因此,假如某個客戶端成功連接服務(wù)器,但是遲遲不調(diào)用writeUTF()方法發(fā)送數(shù)據(jù),服務(wù)器就要一直等待,直到客戶端調(diào)用writeUTF()方法為止,此期間整個服務(wù)器是阻塞的,無法再接受其他客戶端連接,顯然這不符合實際情況。
要解決這個問題,當(dāng)然要用多線程。
如果每個客戶端都獨有一個線程,讓readUTF()方法阻塞客戶端獨有的線程,而不去阻塞服務(wù)器主線程,這樣服務(wù)器就可以同時接受多個客戶端連接,而不用考慮客戶端何時調(diào)用writeUTF()方法發(fā)送數(shù)據(jù)。代碼如下:
服務(wù)器(TCPServer.java):
import java.net.*; import java.io.*; public class TCPServer{ public static void main(String[] args) throws Exception{ ServerSocket ss = new ServerSocket(5566); //創(chuàng)建一個Socket服務(wù)器,監(jiān)聽5566端口 int i=0; //利用死循環(huán)不停的監(jiān)聽端口 while(true){ Socket s = ss.accept();//利用Socket服務(wù)器的accept()方法獲取客戶端Socket對象。 i++; System.out.println("第" + i +"個客戶端成功連接!"); Client c = new Client(i,s); //創(chuàng)建客戶端處理線程對象 Thread t =new Thread(c); //創(chuàng)建客戶端處理線程 t.start(); //啟動線程 } } } //客戶端處理線程類(實現(xiàn)Runnable接口) class Client implements Runnable{ int clientIndex = 0; //保存客戶端id Socket s = null; //保存客戶端Socket對象 Client(int i,Socket s){ clientIndex = i; this.s = s; } public void run(){ //打印出客戶端數(shù)據(jù) try{ DataInputStream dis = new DataInputStream(s.getInputStream()); System.out.println("第" + clientIndex + "個客戶端發(fā)出消息:" + dis.readUTF()); dis.close(); s.close(); } catch(Exception e) {} } }
客戶端(TCPClient.java):
import java.net.*; import java.io.*; public class TCPClient{ public static void main(String[] args) throws Exception{ Socket s = new Socket("192.168.24.177",5566); //創(chuàng)建一個Socket對象,連接IP地址為192.168.24.177的服務(wù)器的5566端口 DataOutputStream dos = new DataOutputStream(s.getOutputStream()); //獲取Socket對象的輸出流,并且在外邊包一層DataOutputStream管道,方便輸出數(shù)據(jù) Thread.sleep((int)(Math.random()*3000)); //讓客戶端不定時向服務(wù)器發(fā)送消息 dos.writeUTF("客戶端消息"); //DataOutputStream對象的writeUTF()方法可以輸出數(shù)據(jù),并且支持中文 dos.flush(); //確保所有數(shù)據(jù)都已經(jīng)輸出 dos.close(); //關(guān)閉輸出流 s.close(); //關(guān)閉Socket連接 } }
運行結(jié)果如下(參考結(jié)果,不一定相同!):
明顯看出第2、3、4客戶端都沒有向服務(wù)器端發(fā)出消息,但都成功連接,而且第2、3、4客戶端向服務(wù)器發(fā)出消息也沒有順序。
通過多線程,實現(xiàn)了多個客戶端同時連接服務(wù)器,并且服務(wù)器能實時處理多個客戶端發(fā)出的消息。
以上僅僅是作為初學(xué)者的一些想法,僅供參考!
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
