java網(wǎng)絡編程之簡單客戶端服務器_第1頁
java網(wǎng)絡編程之簡單客戶端服務器_第2頁
java網(wǎng)絡編程之簡單客戶端服務器_第3頁
java網(wǎng)絡編程之簡單客戶端服務器_第4頁
java網(wǎng)絡編程之簡單客戶端服務器_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、用Java開發(fā)網(wǎng)絡軟件非常方便和強大,Java的這種力量來源于他獨有的一套強大的用于網(wǎng)絡的 API,這些API是一系列的類和接口,均位于包和中。在這篇文章中我們將介紹套接字(Socket)慨念,同時以實例說明如何使用Network API操縱套接字,在完成本文后,你就可以編寫網(wǎng)絡低端通訊軟件。什么是套接字(Socket)?Network API是典型的用于基于TCP/IP網(wǎng)絡Java程序與其他程序通訊,Network API依靠Socket進行通訊。Socket可以看成在兩個程序進行通訊連接中的一個端點,一個程序?qū)⒁欢涡畔懭隨ocket中,該Socket將這

2、段信息發(fā)送給另外一個Socket中,使這段信息能傳送到其他程序中。如圖1我們來分析一下圖1,Host A上的程序A將一段信息寫入Socket中,Socket的內(nèi)容被Host A的網(wǎng)絡管理軟件訪問,并將這段信息通過Host A的網(wǎng)絡接口卡發(fā)送到Host B,Host B的網(wǎng)絡接口卡接收到這段信息后,傳送給Host B的網(wǎng)絡管理軟件,網(wǎng)絡管理軟件將這段信息保存在Host B的Socket中,然后程序B才能在Socket中閱讀這段信息。假設在圖1的網(wǎng)絡中添加第三個主機Host C,那么Host A怎么知道信息被正確傳送到Host B而不是被傳送到Host C中了呢?基于TCP/IP網(wǎng)絡中的每一個主機

3、均被賦予了一個唯一的IP地址,IP地址是一個32位的無符號整數(shù),由于沒有轉(zhuǎn)變成二進制,因此通常以小數(shù)點分隔,如:,正如所見IP地址均由四個部分組成,每個部分的范圍都是0-255,以表示8位地址。值得注意的是IP地址都是32位地址,這是IP協(xié)議版本4(簡稱Ipv4)規(guī)定的,目前由于IPv4地址已近耗盡,所以IPv6地址正逐漸代替Ipv4地址,Ipv6地址則是128位無符號整數(shù)。假設第二個程序被加入圖1的網(wǎng)絡的Host B中,那么由Host A傳來的信息如何能被正確的傳給程序B而不是傳給新加入的程序呢?這是因為每一個基于TCP/IP網(wǎng)絡通訊的程序都被賦予了唯一的端口和端口

4、號,端口是一個信息緩沖區(qū),用于保留Socket中的輸入/輸出信息,端口號是一個16位無符號整數(shù),范圍是0-65535,以區(qū)別主機上的每一個程序(端口號就像房屋中的房間號),低于256的短口號保留給標準應用程序,比如pop3的端口號就是110,每一個套接字都組合進了IP地址、端口、端口號,這樣形成的整體就可以區(qū)別每一個套接字t,下面我們就來談談兩種套接字:流套接字和自尋址數(shù)據(jù)套接字。流套接字(Stream Socket)無論何時,在兩個網(wǎng)絡應用程序之間發(fā)送和接收信息時都需要建立一個可靠的連接,流套接字依靠TCP協(xié)議來保證信息正確到達目的地,實際上,IP包有可能在網(wǎng)絡中丟失或者在傳送過程中發(fā)生錯誤

5、,任何一種情況發(fā)生,作為接受方的 TCP將聯(lián)系發(fā)送方TCP重新發(fā)送這個IP包。這就是所謂的在兩個流套接字之間建立可靠的連接。流套接字在C/S程序中扮演一個必需的角色,客戶機程序(需要訪問某些服務的網(wǎng)絡應用程序)創(chuàng)建一個扮演服務器程序的主機的IP地址和服務器程序(為客戶端應用程序提供服務的網(wǎng)絡應用程序)的端口號的流套接字對象??蛻舳肆魈捉幼值某跏蓟a將IP地址和端口號傳遞給客戶端主機的網(wǎng)絡管理軟件,管理軟件將IP地址和端口號通過NIC傳遞給服務器端主機;服務器端主機讀到經(jīng)過NIC傳遞來的數(shù)據(jù),然后查看服務器程序是否處于監(jiān)聽狀態(tài),這種監(jiān)聽依然是通過套接字和端口來進行的;如果服務器程序處于監(jiān)聽狀態(tài)

6、,那么服務器端網(wǎng)絡管理軟件就向客戶機網(wǎng)絡管理軟件發(fā)出一個積極的響應信號,接收到響應信號后,客戶端流套接字初始化代碼就給客戶程序建立一個端口號,并將這個端口號傳遞給服務器程序的套接字(服務器程序?qū)⑹褂眠@個端口號識別傳來的信息是否是屬于客戶程序)同時完成流套接字的初始化。如果服務器程序沒有處于監(jiān)聽狀態(tài),那么服務器端網(wǎng)絡管理軟件將給客戶端傳遞一個消極信號,收到這個消極信號后,客戶程序的流套接字初始化代碼將拋出一個異常對象并且不建立通訊連接,也不創(chuàng)建流套接字對象。這種情形就像打電話一樣,當有人的時候通訊建立,否則電話將被掛起。這部分的工作包括了相關(guān)聯(lián)的三個類:InetAddress, Socket,

7、和 ServerSocket。 InetAddress對象描繪了32位或128位IP地址,Socket對象代表了客戶程序流套接字,ServerSocket代表了服務程序流套接字,所有這三個類均位于包中。InetAddress類InetAddress類在網(wǎng)絡API套接字編程中扮演了一個重要角色。參數(shù)傳遞給流套接字類和自尋址套接字類構(gòu)造器或非構(gòu)造器方法。InetAddress描述了32位或64位IP地址,要完成這個功能,InetAddress類主要依靠兩個支持類Inet4Address 和 Inet6Address,這三個類是繼承關(guān)系,InetAddrress是父類,Inet4Ad

8、dress 和 Inet6Address是子類。由于InetAddress類只有一個構(gòu)造函數(shù),而且不能傳遞參數(shù),所以不能直接創(chuàng)建InetAddress對象,比如下面的做法就是錯誤的:InetAddress ia = new InetAddress ();但我們可以通過下面的5個工廠方法創(chuàng)建來創(chuàng)建一個InetAddress對象或InetAddress數(shù)組:. getAllByName(String host)方法返回一個InetAddress對象的引用,每個對象包含一個表示相應主機名的單獨的IP地址,這個IP地址是通過host參數(shù)傳遞的,對于指定的主機如果沒有IP地址存在那么這個方法將拋出一個U

9、nknownHostException 異常對象。. getByAddress(byte addr)方法返回一個InetAddress對象的引用,這個對象包含了一個Ipv4地址或Ipv6地址,Ipv4地址是一個4字節(jié)數(shù)組,Ipv6地址是一個16字節(jié)地址數(shù)組,如果返回的數(shù)組既不是4字節(jié)的也不是16字節(jié)的,那么方法將會拋出一個UnknownHostException異常對象。. getByAddress(String host, byte addr)方法返回一個InetAddress對象的引用,這個InetAddress對象包含了一個由host和4字節(jié)的addr數(shù)組指定的IP地址,或者是host和

10、16字節(jié)的addr數(shù)組指定的IP地址,如果這個數(shù)組既不是4字節(jié)的也不是16位字節(jié)的,那么該方法將拋出一個UnknownHostException異常對象。. getByName(String host)方法返回一個InetAddress對象,該對象包含了一個與host參數(shù)指定的主機相對應的IP地址,對于指定的主機如果沒有IP地址存在,那么方法將拋出一個UnknownHostException異常對象。. getLocalHost()方法返回一個InetAddress對象,這個對象包含了本地機的IP地址,考慮到本地主機既是客戶程序主機又是服務器程序主機,為避免混亂,我們將客戶程序主機稱為客戶主機

11、,將服務器程序主機稱為服務器主機。上面講到的方法均提到返回一個或多個InetAddress對象的引用,實際上每一個方法都要返回一個或多個Inet4Address/Inet6Address對象的引用,調(diào)用者不需要知道引用的子類型,相反調(diào)用者可以使用返回的引用調(diào)用InetAddress對象的非靜態(tài)方法,包括子類型的多態(tài)以確保重載方法被調(diào)用。InetAddress和它的子類型對象處理主機名到主機IPv4或IPv6地址的轉(zhuǎn)換,要完成這個轉(zhuǎn)換需要使用域名系統(tǒng),下面的代碼示范了如何通過調(diào)用getByName(String host)方法獲得InetAddress子類對象的方法,這個對象包含了與host參數(shù)

12、相對應的IP地址:InetAddress ia = InetAddress.getByName ();一但獲得了InetAddress子類對象的引用就可以調(diào)用InetAddress的各種方法來獲得InetAddress子類對象中的IP地址信息,比如,可以通過調(diào)用getCanonicalHostName()從域名服務中獲得標準的主機名;getHostAddress()獲得IP地址,getHostName()獲得主機名,isLoopbackAddress()判斷IP地址是否是一個loopback地址。Socket類當客戶程序需要與服務器程序通訊的時候,客戶程序在客戶機

13、創(chuàng)建一個socket對象,Socket類有幾個構(gòu)造函數(shù)。兩個常用的構(gòu)造函數(shù)是 Socket(InetAddress addr, int port) 和 Socket(String host, int port),兩個構(gòu)造函數(shù)都創(chuàng)建了一個基于Socket的連接服務器端流套接字的流套接字。對于第一個InetAddress子類對象通過addr參數(shù)獲得服務器主機的IP地址,對于第二個函數(shù)host參數(shù)包被分配到InetAddress對象中,如果沒有IP地址與host參數(shù)相一致,那么將拋出UnknownHostException異常對象。兩個函數(shù)都通過參數(shù)port獲得服務器的端口號。假設已經(jīng)建立連接了,網(wǎng)

14、絡API將在客戶端基于Socket的流套接字中捆綁客戶程序的IP地址和任意一個端口號,否則兩個函數(shù)都會拋出一個IOException對象。如果創(chuàng)建了一個Socket對象,那么它可能通過調(diào)用Socket的 getInputStream()方法從服務程序獲得輸入流讀傳送來的信息,也可能通過調(diào)用Socket的 getOutputStream()方法獲得輸出流來發(fā)送消息。在讀寫活動完成之后,客戶程序調(diào)用close()方法關(guān)閉流和流套接字,下面的代碼創(chuàng)建了一個服務程序主機地址為,端口號為13的Socket對象,然后從這個新創(chuàng)建的Socket對象中讀取輸入流,然后再關(guān)閉流和Soc

15、ket對象。Socket s = new Socket (, 13);InputStream is = s.getInputStream ();/ Read from the stream.is.close ();s.close ();ServerSocket類由于SSClient使用了流套接字,所以服務程序也要使用流套接字。這就要創(chuàng)建一個ServerSocket對象,ServerSocket有幾個構(gòu)造函數(shù),最簡單的是ServerSocket(int port),當使用ServerSocket(int port)創(chuàng)建一個ServerSocket對象,port參數(shù)傳遞端

16、口號,這個端口就是服務器監(jiān)聽連接請求的端口,如果在這時出現(xiàn)錯誤將拋出IOException異常對象,否則將創(chuàng)建ServerSocket對象并開始準備接收連接請求。接下來服務程序進入無限循環(huán)之中,無限循環(huán)從調(diào)用ServerSocket的accept()方法開始,在調(diào)用開始后accept()方法將導致調(diào)用線程阻塞直到連接建立。在建立連接后accept()返回一個最近創(chuàng)建的Socket對象,該Socket對象綁定了客戶程序的IP地址或端口號。由于存在單個服務程序與多個客戶程序通訊的可能,所以服務程序響應客戶程序不應該花很多時間,否則客戶程序在得到服務前有可能花很多時間來等待通訊的建立,然而服務程序和

17、客戶程序的會話有可能是很長的(這與電話類似),因此為加快對客戶程序連接請求的響應,典型的方法是服務器主機運行一個后臺線程,這個后臺線程處理服務程序和客戶程序的通訊。下面給出一個客戶端和服務器的程序,客戶端向服務器發(fā)送數(shù)據(jù),服務器接收數(shù)據(jù)并用它生成一個結(jié)果,然后將結(jié)果返回給客戶端,并在控制臺上顯示。服務器代碼java 1. packageServer;2. 3. importjava.io.*;4. .*;5. importjava.util.*;6. importjava.awt.*;7. importjavax.swing.*;8. 9. publicclassS

18、erverextendsJFrame10. /Textareafordisplayingcontents11. privateJTextAreajta=newJTextArea();12. 13. publicstaticvoidmain(Stringargs)14. newServer();15. 16. 17. publicServer()18. /Placetextareaontheframe19. getContentPane().setLayout(newBorderLayout();20. getContentPane().add(newJScrollPane(jta),Borde

19、rLayout.CENTER);21. 22. setTitle(Server);23. setSize(500,300);24. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);25. setVisible(true);/Itisnecessarytoshowtheframehere!26. 27. try28. /Createaserversocket29. ServerSocketserverSocket=newServerSocket(8000);30. jta.append(Serverstartedat+newDate()+n);31.

20、 32. /Listenforaconnectionrequest33. Socketsocket=serverSocket.accept();34. 35. /Createdatainputandoutputstreams36. DataInputStreaminputFromClient=newDataInputStream(37. socket.getInputStream();38. DataOutputStreamoutputToClient=newDataOutputStream(39. socket.getOutputStream();40. 41. while(true)42.

21、 /Receiveradiusfromtheclient43. doubleradius=inputFromClient.readDouble();44. 45. /Computearea46. doublearea=radius*radius*Math.PI;47. 48. /Sendareabacktotheclient49. outputToClient.writeDouble(area);50. 51. jta.append(Radiusreceivedfromclient:+radius+n);52. jta.append(Areafound:+area+n);53. 54. 55.

22、 catch(IOExceptionex)56. System.err.println(ex);57. 58. 59. 客戶端程序java1. packageClient;2. 3. importjava.io.*;4. .*;5. importjava.awt.*;6. importjava.awt.event.*;7. importjavax.swing.*;8. 9. publicclassClientextendsJFrameimplementsActionListener10. /Textfieldforreceivingradius11. private

23、JTextFieldjtf=newJTextField();12. 13. /Textareatodisplaycontents14. privateJTextAreajta=newJTextArea();15. 16. /IOstreams17. privateDataOutputStreamoutputToServer;18. privateDataInputStreaminputFromServer;19. 20. publicstaticvoidmain(Stringargs)21. newClient();22. 23. 24. publicClient()25. /Panelpto

24、holdthelabelandtextfield26. JPanelp=newJPanel();27. p.setLayout(newBorderLayout();28. p.add(newJLabel(Enterradius),BorderLayout.WEST);29. p.add(jtf,BorderLayout.CENTER);30. jtf.setHorizontalAlignment(JTextField.RIGHT);31. 32. getContentPane().setLayout(newBorderLayout();33. getContentPane().add(p,Bo

25、rderLayout.NORTH);34. getContentPane().add(newJScrollPane(jta),BorderLayout.CENTER);35. 36. jtf.addActionListener(this);/Registerlistener37. 38. setTitle(Client);39. setSize(500,300);40. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);41. setVisible(true);/Itisnecessarytoshowtheframehere!42. 43. try4

26、4. /Createasockettoconnecttotheserver45. Socketsocket=newSocket(localhost,8000);46. /Socketsocket=newSocket(6,8000);47. /Socketsocket=newSocket(drake.A,8000);48. 49. /Createaninputstreamtoreceivedatafromtheserver50. inputFromServer=newDataInputStream(51. socket.getInputStrea

27、m();52. 53. /Createanoutputstreamtosenddatatotheserver54. outputToServer=55. newDataOutputStream(socket.getOutputStream();56. 57. catch(IOExceptionex)58. jta.append(ex.toString()+n);59. 60. 61. 62. publicvoidactionPerformed(ActionEvente)63. StringactionCommand=e.getActionCommand();64. if(e.getSource

28、()instanceofJTextField)65. try66. /Gettheradiusfromthetextfield67. doubleradius=Double.parseDouble(jtf.getText().trim();68. 69. /Sendtheradiustotheserver70. outputToServer.writeDouble(radius);71. outputToServer.flush();72. 73. /Getareafromtheserver74. doublearea=inputFromServer.readDouble();75. 76.

29、/Displaytothetextarea77. jta.append(Radiusis+radius+n);78. jta.append(Areareceivedfromtheserveris79. +area+n);80. 81. catch(IOExceptionex)82. System.err.println(ex);83. 84. 85. 86. 運行結(jié)果如下如所在做一個服務器服務多個客戶端時,可以簡單的為買個客戶端創(chuàng)建一個線程。相互獨立的線程和指定的客戶端進行通信,每個線程創(chuàng)建數(shù)據(jù)輸入輸出流向客戶端發(fā)送接收數(shù)據(jù)。多線程服務器端的代碼如下:java 1. packageMultiT

30、hreadServer;2. 3. importjava.io.*;4. .*;5. importjava.util.*;6. importjava.awt.*;7. importjavax.swing.*;8. 9. publicclassMultiThreadServerextendsJFrame10. /Textareafordisplayingcontents11. privateJTextAreajta=newJTextArea();12. 13. publicstaticvoidmain(Stringargs)14. newMultiThreadServ

31、er();15. 16. 17. publicMultiThreadServer()18. /Placetextareaontheframe19. getContentPane().setLayout(newBorderLayout();20. getContentPane().add(newJScrollPane(jta),BorderLayout.CENTER);21. 22. setTitle(MultiThreadServer);23. setSize(500,300);24. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);25. set

32、Visible(true);/Itisnecessarytoshowtheframehere!26. 27. try28. /Createaserversocket29. ServerSocketserverSocket=newServerSocket(8000);30. jta.append(MultiThreadServerstartedat+newDate()+n);31. 32. /Numberaclient33. intclientNo=1;34. 35. while(true)36. /Listenforanewconnectionrequest37. Socketsocket=s

33、erverSocket.accept();38. 39. /Displaytheclientnumber40. jta.append(Startingthreadforclient+clientNo+41. at+newDate()+n);42. 43. /Findtheclientshostname,andIPaddress44. InetAddressinetAddress=socket.getInetAddress();45. jta.append(Client+clientNo+shostnameis46. +inetAddress.getHostName()+n);47. jta.append(Client+clientNo+sIPAddressis48. +inetAddress.getHostAddress()+n);49. 50. /Createanewthreadfortheconnection51. Ha

溫馨提示

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

評論

0/150

提交評論