Java Socket聊天程序核心代碼講解
Java Socket聊天程序在編寫(xiě)的時(shí)候需要我們注意很多的事情,本程序是基于Java Socket聊天程序,采用TCP傳輸協(xié)議,實(shí)現(xiàn)兩個(gè)人之間的信息交互。下面我們就詳細(xì)的向大家介紹這一程序。#t#
在形成最終結(jié)果之前,我經(jīng)歷了兩個(gè)過(guò)程程序,兩個(gè)過(guò)程均為半成品,他們反映了我整個(gè)課程設(shè)計(jì)中的思考過(guò)程,在一個(gè)較為系統(tǒng)思考過(guò)程后,socket思想一層一層加固,讓我映像很深刻,收獲很多。在此文檔中,我將演示我兩個(gè)過(guò)程程序的思考過(guò)程,然后對(duì)源代碼進(jìn)行講解,但最終上傳的代碼為制成品。
在兩個(gè)過(guò)程程序中,TestServer1和TestClient1為***個(gè)過(guò)程,TestServer2和TestClient2為第二個(gè)過(guò)程,MySingleThreadServer1和MySingleThreadClient1為最終程序。其中,TestServer2和TestClient2實(shí)現(xiàn)了多線程,一個(gè)線程負(fù)責(zé)接收,另一個(gè)線程負(fù)責(zé)發(fā)送,MySingleThreadServer1和MySingleThreadClient1實(shí)現(xiàn)了基于GUI的聊天。控件并非像MFC那樣很容易就可以通過(guò)拖動(dòng)組件實(shí)現(xiàn),java是通過(guò)程序的編寫(xiě)來(lái)實(shí)現(xiàn),我采用awt組件編碼實(shí)現(xiàn)GUI,界面很簡(jiǎn)單,但花了不少時(shí)間來(lái)布局。
核心代碼講解:
三個(gè)過(guò)程程序都牽涉了Java Socket聊天程序最核心的思想,以下為核心的講解。
1.服務(wù)器端
Java Socket服務(wù)器端需要引入兩個(gè)包,java.io包和java.net包,io包是解決輸入輸出流的問(wèn)題,而net包包含了socket編程所需的API.服務(wù)器端首先要得到ServerSocket的對(duì)象,即ServerSocket ss = new ServerSocket(5555); 5555為服務(wù)器端的端口號(hào)。Socket s = ss.accept();服務(wù)器端Socket對(duì)象通過(guò)accept()方法開(kāi)始監(jiān)聽(tīng)鏈接過(guò)來(lái)的客戶端信息。如果有客戶端有信息過(guò)來(lái),則對(duì)象s調(diào)用輸入輸出流的方法,如s.getInputStream(),同時(shí)把得到的InputStream 封裝在DataInputStream當(dāng)中,在客戶端與服務(wù)器端通信時(shí),有可能兩端存在于不同的操作系統(tǒng),封裝在DataInputStream可以很好的解決這個(gè)問(wèn)題。
2.客戶端
其實(shí)客戶端代碼與服務(wù)器端大多類似,有一點(diǎn)顯著不同,在客戶端沒(méi)有ServerSocket類,即客戶端不用監(jiān)聽(tīng)任何鏈接,他只需要發(fā)送鏈接即可。Socket s = new Socket(String IPAddr,int port),IPAddr為服務(wù)器端的IP地址,port為服務(wù)器端的端口號(hào)即5555,由于本程序服務(wù)器端和客戶端在同一主機(jī)上,所以服務(wù)器端IP地址為127.0.0.1。通過(guò)IPAddr和port兩個(gè)參數(shù)就可以得到Java Socket聊天程序?qū)ο髎,接下來(lái)的步驟就和服務(wù)器程序類似了。
對(duì)三個(gè)過(guò)程程序的詳解
Procedure1:服務(wù)器端核心代碼如下:
- ServerSocket ss = new ServerSocket(5555);
- Socket s = ss.accept();
- OutputStream os = s.getOutputStream();
- DataOutputStream dos = new DataOutputStream(os);
- InputStream is = s.getInputStream();
- DataInputStream dis = new DataInputStream(is);
- InputStreamReader isr = new InputStreamReader(System.in);
//重鍵盤(pán)讀入數(shù)據(jù)- BufferedReader br = new BufferedReader(isr);
//把從鍵盤(pán)讀入的數(shù)據(jù)放入緩沖- String info;
- while(true){
- info = dis.readUTF();
- System.out.println("客戶端說(shuō):" + info);
- if(info.equals("goodbye")){
- break;
- }
- info = br.readLine();
- dos.writeUTF(info);
- System.out.println("服務(wù)器說(shuō):" + info);
- if(info.equals("goodbye")){
- break;
- }
- }
客戶端核心代碼如下:
- Socket s = new Socket("127.0.0.1",5555);
- InputStream is = s.getInputStream();
- DataInputStream dis = new DataInputStream(is);
- OutputStream os = s.getOutputStream();
- DataOutputStream dos = new DataOutputStream(os);
- InputStreamReader isr = new InputStreamReader(System.in);
- BufferedReader br = new BufferedReader(isr);
- String info;
- while(true){
- info = br.readLine();
- System.out.println("客戶端說(shuō)的是:" + info);
- dos.writeUTF(info);
- if(info.equals("goodbye")){
- break;
- }
- info = dis.readUTF(); //阻塞函數(shù)
- System.out.println("服務(wù)器端說(shuō)的是:" + info);
- if(info.equals("goodbye")){
- break;
- }
- }
服務(wù)器端和客戶端在while(true)循環(huán)處各不相同,服務(wù)器端是dis.readUTF(),必須首先讀取客戶端傳過(guò)來(lái)的信息,才能通過(guò)info = br.readLine();dos.writeUTF(info);從鍵盤(pán)中讀取信息再發(fā)送給客戶端。相反,客戶端必須首先通過(guò)br.readLine();讀取鍵盤(pán)信息,才能接收服務(wù)器發(fā)送來(lái)的信息。
思考1:這個(gè)簡(jiǎn)易的聊天程序已經(jīng)實(shí)現(xiàn)了服務(wù)器和客戶端的信息交互,但此時(shí)已經(jīng)出現(xiàn)了一個(gè)必然出現(xiàn)的問(wèn)題,比如拿服務(wù)器端來(lái)講,當(dāng)服務(wù)器通過(guò)dos.writeUTF(info)發(fā)送消息給客戶端后,在while循環(huán)體內(nèi),他又要執(zhí)行info = dis.readUTF()代碼,而readUTF()是一個(gè)阻塞函數(shù),如果客戶端沒(méi)有發(fā)送過(guò)來(lái),他就阻塞在那個(gè)地方,此時(shí)下面部分的代碼dos.writeUTF(info)就不能執(zhí)行,即服務(wù)器端不能發(fā)送消息出去。
Java Socket聊天程序要怎樣解決這個(gè)問(wèn)題呢?怎樣readUTF()阻塞的同時(shí)又可以writeUTF(info)發(fā)送出消息呢?顯然,一條路徑走不通時(shí)應(yīng)該考慮走另一條路,于是,多線程在這里引入了。Procedure2就是這樣出來(lái)的。