基于UDP協議網上聊天程序_第1頁
基于UDP協議網上聊天程序_第2頁
基于UDP協議網上聊天程序_第3頁
基于UDP協議網上聊天程序_第4頁
基于UDP協議網上聊天程序_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

《計算機網絡》課程設計說明書題目:基于UDP協議網上聊天程序學院:計算機科學與工程學院專業(yè):信息平安姓名:學號:1000360222指導教師:孫晉永目錄1協議介紹和使用說明31.1協議內容31.2關鍵技術41.2.1效勞器端Socket的實現41.2.2通信的建立52程序設計62.1系統(tǒng)結構62.2主程序設計72.2.1效勞器端程序72.2.2客戶端程序72.3各模塊設計8客戶端向效勞器發(fā)送消息8客戶端之間發(fā)送消息82.4界面設計82.4.1聊天界面設計的方法82.4.2界面的功能92.5實現主要代碼92.6程序調試及運行結果152.6.1調試前的準備152.6.2程序調試過程162.6.3程序運行結果163課設體會17參考文獻181協議介紹和使用說明1.1協議內容本課程設計主要是基于UDP的并用Java實現的簡單的聊天程序。UDP用戶數據報是在運輸層的端到端抽象的邏輯信道中傳送的。UDP在傳送數據之前不需要先建立連接。對方的運輸層在收到UDP報文后,不需要給出任何確認。雖然UDP不提供可靠交付,但在某些情況下UDP是一種最有效的工作方式。雖然UDP用戶數據報只能提供不可靠的交付,但UDP在某些方面有其特殊的優(yōu)點,它有即時通信的功能。比方說,使用聊天程序聊天的時候,省去的了跟對方通信的時候的鏈接的麻煩,直接進行通信。UDP只在IP的數據報效勞之上增加了很少一點的功能,即端口的功能和過失檢測的功能。UDP使用盡最大努力交付,即不保證可靠交付,同時也不使用擁塞控制。UDP是面向報文的。UDP沒有擁塞控制,很適合多媒體通信的要求。UDP支持一對一、一對多、多對一和多對多的交互通信。發(fā)送方UDP對應用程序交下來的報文,在添加首部后就向下交付IP層。UDP對應用層交下來的報文,既不合并,也不拆分,而是保存這些報文的邊界。應用層交給UDP多長的報文,UDP就照樣發(fā)送,即一次發(fā)送一個報文。接收方UDP對IP層交上來的UDP用戶數據報,在去除首部后就原封不動地交付上層的應用進程,一次交付一個完整的報文。圖1.1UDP根本工作過程1.2關鍵技術效勞器端Socket的實現Socket又稱作套接字,它是使用標準Unix

文件描述符(file

descriptor)

和其它程序通訊的方式。使用send()和recv()讓你更好的控制數據傳輸。在Java網絡編程中,socket相當于應用程序的港口碼頭;在計算機網絡中,套接字由ip地址和端口號組成,為進程之間通信提供地址。兩個主機進行通信實際上就是兩個主機中的應用進程互相通信,應用進程之間的通信又稱為端到端的通信。為應用進程之間的通信提供運輸效勞的是運輸層的運輸協議,運輸層需要有兩種不同的運輸協議,即面向連接的TCP和無連接的UDP。在Java中,用于實現基于UDP的聊天程序,使用兩個重要的類〔DatagramSocket類和DatagramPacket類〕。DatagramSocket類表示用來發(fā)送和接收數據報包的套接字。數據報套接字是包投遞效勞的發(fā)送或接收點。每個在數據報套接字上發(fā)送或接收的包都是單獨編址和路由的。從一臺機器發(fā)送到另一臺機器的多個包可能選擇不同的路由,也可能按不同的順序到達。在DatagramSocket上總是啟用UDP播送發(fā)送。為了接收播送包,應該將DatagramSocket綁定到通配符地址。在某些實現中,將DatagramSocket綁定到一個更加具體的地址時播送包也可以被接收。atagramPacket類表示數據報包。數據報包用來實現無連接包投遞效勞。每條報文僅根據該包中包含的信息從一臺機器路由到另一臺機器。從一臺機器發(fā)送到另一臺機器的多個包可能選擇不同的路由,也可能按不同的順序到達。不對包投遞做出保證。效勞程序工作在效勞器的某個端口上,一旦啟動效勞,它將在這個端口上監(jiān)聽,等待客戶程序發(fā)來請求,當有客戶連接到該端口,accept〔〕方法就返回一個Socket對象,可以用該對象獲得一個輸入輸出流。效勞器的套接字用效勞器套接字類〔ServerSocket〕來建立。具體實現如下:(1)建立一個效勞者,端口為5000。(2)效勞者永遠等待,一旦客戶送來正確的請求,連接至該端口,accept〔〕方法就返回一個Socket對象。(3)用返回的Socket對象創(chuàng)立數據輸入流類的實例in。用返回的Socket對象創(chuàng)立數據輸出流的實例out。以上實例in和out是效勞者用于從客戶接受輸入信息和向客戶程序發(fā)送信息所用。此外,還需要用方法readline〔〕和println〔〕讀取或輸出一行數據。(4)soc.close〔〕關閉Socket。圖1.2基于UDP的SOCKET編程模型通信的建立在客戶端建立Socket對象,并進行異常處理,主機名和端口號與連接的效勞器名和提供該效勞的效勞程序的監(jiān)聽端口必須一致。建立連接后用Socket類提供的getInputStream〔〕和getOutputStream〔〕方法取得輸入輸出流。在效勞器端,獲得的輸入流是客戶端的輸出流,而Socket獲得的輸出流是發(fā)向客戶端的輸入流,在客戶端也是這樣。獲得socket的輸入輸出流之后,為了便于讀寫操作,需要在這兩個流對象根底上建立易于操作的數據流DateInputStream,DataOutputStream。然后對輸入輸出流進行讀寫操作。在通信結束時關閉socket,以斷開連接,釋放資源。先關閉對應的輸入輸出流,再關閉socket本身。2程序設計2.1系統(tǒng)結構本系統(tǒng)采用一個效勞器端和多個客戶端的聊天方式來實現。結構圖如下所示:圖2.1效勞器-客戶端結構圖2.2主程序設計效勞器端程序效勞器與客戶間通過套接口Socket連接。在java中使用套接口相當簡單,JavaAPI為處理套接口的通信提供了一個類.Socket.,使得編寫網絡應用程序相對容易.效勞器采用多線程以滿足多用戶的請求,程序用vector向量數組存儲連接客戶變量,通過創(chuàng)立一個ServerSocket對象來監(jiān)聽來自客戶的連接請求,默認端口為6666,然后無限循環(huán)調用accept()方法接受客戶程序的連接??蛻舳顺绦蚩蛻舳耸且粋€JavaApplet程序,客戶通過Socket建立與效勞器的連接。圖2.2主程序流程圖2.3各模塊設計客戶端向效勞器發(fā)送消息效勞器與客戶都通過構造DataInputStream,PrintStream來建立輸入輸出流,然后雙方通過該輸入輸出流來相互傳遞信息,一旦收到客戶方的連接請求,效勞器accept()方法返回一個新建的Socket對象??蛻舳巳缓笙蛐谄靼l(fā)送消息,客戶端之間發(fā)送消息客戶間發(fā)送信息通過UDP協議來實現,用戶登錄時通過類DatagramPacket和DatagramSocket創(chuàng)立UDP包括其本地接受端口以及發(fā)送端口,默認端口為newDatagramSocket〔〕和nickNameField.getText〔〕,通過向效勞器發(fā)送消息,然后效勞器播送消息,最好到達群聊的目的。客戶端發(fā)送消息〔send(DatagramPacket)和接受消息(receive(DatagramPacket))。2.4界面設計2.4.1聊天界面設計的方法在Frame布局容器中,添加一個顯示聊天的TextArea文本框〔在上面〕,參加Panel面板,Panel面板中包括一個發(fā)送消息的TextField單行文本框,“聊天記錄〞和“發(fā)送〞兩個按鈕監(jiān)聽。圖2.3聊天界面實現功能圖2.4.2界面的功能①客戶端登陸界面輸入效勞器IP,接收端口,及用戶名。登陸效勞器,與效勞器建立連接,進入聊天界面。②客戶端聊天界面,進行聊天。并可查看聊天記錄。③效勞器界面,監(jiān)聽客戶端連接狀況并可發(fā)送效勞器消息。2.5實現主要代碼客戶端代碼:packageudp;importjava.io.*;importjava.awt.*;importjava.awt.event.*;import.*;classClientimplementsActionListener,Runnable{privateFrameframe,f1,f2;//聊天窗口和登陸窗口privatePanelp1,p2,p3;privateButtonsendButton,b,c,d;privateTextFieldserverIpField,sendField,receivePortField,nickNameField;privateTextAreacurrentUserField;booleanisClient=false;privateTextAreamessageArea;//聊天記錄框privateStringserverIp;privateintserverReceivePort=6666;//效勞器接收默認端口privateDatagramSocketreceiveSocket=null,sendSocket=null;privateDatagramPacketreceivePacket=null,sendPacket=null;//客戶端登陸界面publicvoidinputIP(){ }//聊天記錄界面publicvoidinput(){ }//客戶端聊天界面publicvoidlaunchFrame(){ }//啟動客戶端,完成登錄publicvoidstart(){try{sendSocket=newDatagramSocket();//客戶機發(fā)送端口 sendMessage(nickNameField.getText()+":" +receivePortField.getText()+":");//名字和接收端口newThread(this).start(); }catch(Exceptione){messageArea.append(e+"\n"); } }//客戶端發(fā)送消息publicvoidsendMessage(Stringstr){try{ ByteArrayOutputStreamout=newByteArrayOutputStream();//捕獲內存緩沖區(qū)的數據,轉換成字節(jié)數組 PrintStreampout=newPrintStream(out);//輸出字節(jié) pout.print(str);byte[]buf=out.toByteArray();sendPacket=newDatagramPacket(buf,buf.length,InetAddress .getByName(serverIp),serverReceivePort);//構造數據報包sendSocket.send(sendPacket);//發(fā)送數據報包 buf=null; }catch(Exceptione){ e.printStackTrace();messageArea.append("消息:"+str+"發(fā)送失敗,你還沒有登錄,或已經掉線!\n"); } }//多線程,啟動接收信息publicvoidrun(){ receiveMessage(); }//客戶機接收消息publicvoidreceiveMessage() {try{receiveSocket=newDatagramSocket(Integer .parseInt(receivePortField.getText()));//客戶機接受端口while(true){byte[]buf=newbyte[200];receivePacket=newDatagramPacket(buf,buf.length);receiveSocket.receive(receivePacket);if(receivePacket.getLength()==0){messageArea.append("空消息"+"\n");continue; } ByteArrayInputStreambin=newByteArrayInputStream(receivePacket.getData());//字節(jié)串變成輸入流 BufferedReaderread=newBufferedReader(newInputStreamReader( bin));//先把字節(jié)流轉換為字符流,然后放入緩沖區(qū) Stringstr=read.readLine();messageArea.append(str);if(str.contains("迎:/")){ }messageArea.append("\n"); read.close(); bin.close(); } }catch(Exceptione){messageArea.append(e+"sendmessageerror\n");} }//事件響應處理publicvoidactionPerformed(ActionEvente){ }//程序主入口publicstaticvoidmain(String[]args){ Clientclient=newClient();//client.input(); client.inputIP(); }效勞端端代碼:packageudp;importjava.io.*;importjava.awt.*;importjava.awt.event.*;import.*;importjava.util.ArrayList;importjava.util.Date;importjava.util.List;importjava.util.Iterator;publicclassServerimplementsActionListener{privateFrameframe;//主窗體privateLabelconnectLabel,messageLabel;privateTextAreamessageArea;//消息框,顯示用戶登錄信息privateTextFieldsendField;//輸入聊天內容的文本框privateButtonsendButton;//發(fā)送按鈕privateDatagramSocketreceiveSocket=null,sendSocket=null;privateDatagramPacketreceivePacket=null,sendPacket=null;privateintserverReceivePort=6666;//效勞器端的接收端口privateList<ClientMessage>clientList=newArrayList<ClientMessage>();//保存連接的客戶端信息booleanisServer=true;//程序主入口publicstaticvoidmain(String[]args){ Serverserver=newServer(); server.launchFrame(); server.start();//啟動效勞器 server.receiveMessage();//接收信息 }//效勞端界面初始化publicvoidlaunchFrame(){ }//事件監(jiān)聽處理publicvoidactionPerformed(ActionEvente){ } }//啟動效勞器publicvoidstart(){try{sendSocket=newDatagramSocket(6660);//效勞器發(fā)送端口 }catch(Exceptione){messageArea.append(e+"\n"); } }//效勞器接收消息publicvoidreceiveMessage() {try{receiveSocket=newDatagramSocket(serverReceivePort);//效勞器接受端口while(true){byte[]buf=newbyte[200];receivePacket=newDatagramPacket(buf,buf.length);receiveSocket.receive(receivePacket);intlength=clientList.size();booleanhave=false; ByteArrayInputStreambin=newByteArrayInputStream(receivePacket.getData()); BufferedReaderread=newBufferedReader(newInputStreamReader( bin)); Stringstr=read.readLine();for(inti=0;i<length;i++){ ClientMessageoldMsg=clientList.get(i);if(oldMsg.hasClient(receivePacket.getPort(),receivePacket.getAddress())){ have=true;break; } }//未存在此客戶端if(!have){ ClientMessagenewMsg=newClientMessage( Integer.parseInt(str.split(":")[1].trim()),receivePacket.getPort(),receivePacket.getAddress());messageArea.append("用戶:"+str.split(":")[0] +"進入聊天室,其IP地址:" +receivePacket.getAddress().getHostAddress() +"發(fā)送端口:"+newMsg.getSendPort()+"接收端口:" +newMsg.getReceivePort()+"登錄時間:" +newDate()+"\n");clientList.add(newMsg); sendMessage("熱烈歡送:"+str.split(":")[0]+"IP:" +receivePacket.getAddress().getHostAddress() +"參加聊天室!\n"); }else{//用戶已經存在 sendMessage(str); } read.close(); bin.close(); } }catch(Exceptione){///e.printStackTrace();messageArea.append(e+"sendmessageerror\n"); } }//效勞器端發(fā)送消息給客戶端publicvoidsendToClient(){ }//效勞器播送消息publicvoidsendMessage(Stringstr){ ByteArrayOutputStreamout=newByteArrayOutputStream(); PrintStreampout=newPrintStream(out); pout.print(str);byte[]buf=out.toByteArray();//緩沖區(qū)intlength=clientList.size();try{//轉發(fā)給每一個在線用戶for(inti=0;i<length;i++){ ClientMessagemsg=clientList.get(i);sendPacket=newDatagramPacket(buf,buf.length, msg.getClientIp(),msg.getReceivePort());sendSocket.send(sendPacket); } }catch(IOExceptione){ e.printStackTrace(); } buf=null; }}classClientMessage{privateintreceivePort;//客戶端的接收端口privateintsendPort;//客戶端的發(fā)送端口privateInetAddressclientIp;//客戶端的IPpublicClientMessage(intreceivePort,intsendPort,InetAddressclientIp){this.receivePort=receivePort;this.clientIp=clientIp;this.sendPort=sendPort; }publicintgetReceivePort(){returnreceivePort; }publicInetAddressgetClientIp(){returnclientIp; }publicintgetSendPort(){returnsendPort; }publicbooleanhasClient(intsendPort,InetAddressip){if(ip.getHostAddress().equals(this.getClientIp().getHostAddress()) &&sendPort==this.getSendPort()){returntrue; }returnfalse; }}2.6程序調試及運行結果2.6.1調試前的準備安裝jdk并在計算機的環(huán)境變量中配置好java環(huán)境。使用的實驗環(huán)境是Windows7,EclipseSDK版本:,。2.6.2程序調試過程啟動eclipse,單機測試。首先在主機上運行效勞器端程序,再在器上運行3個客戶端程序。然后進入到用戶的圖形用戶界面,輸入效勞器的IP,進行連接,如果連接成功,那么客戶端就可以通過與效勞器端進行通信,然后效勞器轉發(fā)通信,實現了多個客戶之間的聊天

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論