隨筆 - 312, 文章 - 14, 評(píng)論 - 1393, 引用 - 0
          數(shù)據(jù)加載中……

          Java網(wǎng)絡(luò)編程從入門到精通(14):多種多樣的建立網(wǎng)絡(luò)連接的方式

          本文為原創(chuàng),如需轉(zhuǎn)載,請(qǐng)注明作者和出處,謝謝!

          上一篇:Java網(wǎng)絡(luò)編程從入門到精通(13):使用Socket類接收和發(fā)送數(shù)據(jù)

          在上一篇文章中我們討論了Socket類的基本用法,并給出的例子中使用Socket類連接服務(wù)器時(shí)使用了一種最簡(jiǎn)單的連接方式,也就是通過(guò)IP和端口號(hào)來(lái)連接服務(wù)器。而為了使連接服務(wù)器的方式更靈活,Socket類不僅可以通過(guò)自身的構(gòu)造方法連接服務(wù)器,而且也可以通過(guò)connect方法來(lái)連接數(shù)據(jù)庫(kù)。

          一、通過(guò)構(gòu)造方法連接服務(wù)器

              我們可以通過(guò)6個(gè)重載構(gòu)造函數(shù)以不同的方式來(lái)連接服務(wù)器。這6個(gè)重載的構(gòu)造函數(shù)可以分為兩類:

          1.
          自動(dòng)選擇IP

              這種方式是最常用的。所謂自動(dòng)選擇
          IP,是指當(dāng)本機(jī)有多塊網(wǎng)卡或者在一個(gè)網(wǎng)卡上綁定了多個(gè)IP時(shí),Socket類會(huì)自動(dòng)為我們選擇一個(gè)可用的IP。在上述6個(gè)構(gòu)造方法中有4個(gè)是使用這種方法來(lái)連接服務(wù)器的。

          (1)    public Socket(String host, int port)

          這是最常用的構(gòu)造方法,在前面的例子中就是使用的這個(gè)構(gòu)造方法。在使用時(shí)只需要提供一個(gè)字符串類型的IP或域名以及一個(gè)整型的端口號(hào)即可。在這個(gè)構(gòu)造方法中可能會(huì)拋出兩個(gè)錯(cuò)誤:UnknownHostExceptionIOException。發(fā)生第一個(gè)錯(cuò)誤的原因是我們提供的host并不存在或不合法,而其它的錯(cuò)誤被歸為IO錯(cuò)誤。因此,這個(gè)構(gòu)造方法的完整定義是:

          public Socket(String host, int port) throws UnknownHostException, IOException

          (2) public Socket(InetAddress inetaddress, int port)

          這個(gè)構(gòu)造方法和第一種構(gòu)造方法類似只是將字符串形式的host改為InetAddress對(duì)象類型了。在這個(gè)構(gòu)造方法中之所以要使用InetAddress類主要是因?yàn)榭紤]到在程序中可能需要使用Socket類多次連接同一個(gè)IP或域名,這樣使用InetAddress類的效率比較高。另外,在使用字符串類型的host連接服務(wù)器時(shí),可能會(huì)發(fā)生兩個(gè)錯(cuò)誤,但使用InetAddress對(duì)象來(lái)描述host,只會(huì)發(fā)生IOException錯(cuò)誤,這是因?yàn)楫?dāng)你將IP或域名傳給InetAddress時(shí),InetAddress會(huì)自動(dòng)檢查這個(gè)IP或域名,如果這個(gè)IP或域名無(wú)效,那么InetAddress就會(huì)拋出UnknownHostException錯(cuò)誤,而不會(huì)由Socket類的構(gòu)造方法拋出。因此,這個(gè)構(gòu)造方法的完整定義是:

          public Socket(InetAddress inetaddress, int port) throws IOException

          (3) public Socket(String host, int port, boolean stream)

          這個(gè)構(gòu)造方法和第一種構(gòu)造方法差不多,只是多了一個(gè)boolean類型的stream參數(shù)。如果這個(gè)streamtrue,那么這個(gè)構(gòu)造方法和第一種構(gòu)造方法完全一樣。如果streamfalse,則使用UDP協(xié)議建立一個(gè)UDP連接(UDP將在下面的章節(jié)詳細(xì)討論,在這里只要知道它和TCP最大的區(qū)別是UDP是面向無(wú)連接的,而TCP是面向有連接的),也許是當(dāng)初Sun的開發(fā)人員在編寫Socket類時(shí)還未考慮編寫處理UDP連接的DatagramSocket類,所以才將建立UDP連接的功能加入到Socket類中,不過(guò)Sun在后來(lái)的JDK中加入了DatagramSocket類,所以,這個(gè)構(gòu)造方法就沒什么用了,因此,Sun將其設(shè)為了Deprecated標(biāo)記,也就是說(shuō),這個(gè)構(gòu)造方法在以后的JDK版本中可以會(huì)被刪除。其于以上原因,在使用Java編寫網(wǎng)絡(luò)程序時(shí),盡量不要使用這個(gè)構(gòu)造方法來(lái)建立UDP連接。

          (4) public Socket(InetAddress inetaddress, int port, boolean flag)

          這個(gè)構(gòu)造方法和第三種構(gòu)造方法的flag標(biāo)記的含義一樣,也是不建議使用的。

              下面的代碼演示
          上述4種構(gòu)造方法的使用:

          package mysocket;

          import java.net.*;
          import java.io.*;

          public class MoreConnection
          {
              
          private static void closeSocket(Socket socket)
              {
                  
          if (socket != null)
                      
          try
                      {
                          socket.close();
                      }
                      
          catch (Exception e) { }
              }

              
          public static void main(String[] args)
              {
                  Socket socket1 
          = null, socket2 = null, socket3 = null, socket4 = null;
                  
          try
                  {
                      
          // 如果將www.ptpress.com.cn改成其它不存在的域名,將拋出UnknownHostException錯(cuò)誤
                      
          // 測(cè)試public Socket(String host, int port)
                      socket1 = new Socket("www.ptpress.com.cn"80);
                      System.out.println(
          "socket1連接成功!");
                      
          // 測(cè)試public Socket(InetAddress inetaddress, int port)
                      socket2 = new Socket(InetAddress.getByName("www.ptpress.com.cn"), 80);
                      System.out.println(
          "socket2連接成功!");

                      
          // 下面的兩種建立連接的方式并不建議使用
                      
          // 測(cè)試public Socket(String host, int port, boolean stream)
                      socket3 = new Socket("www.ptpress.com.cn"80false);
                      System.out.println(
          "socket3連接成功!");
                      
          // 測(cè)試public Socket(InetAddress inetaddress, int i, boolean flag)
                      socket4 = new Socket(InetAddress.getByName("www.ptpress.com.cn"), 80false);
                      System.out.println(
          "socket4連接成功!");
                  }
                  
          catch (UnknownHostException e)
                  {
                      System.out.println(
          "UnknownHostException 被拋出!");
                  }
                  
          catch (IOException e)
                  {
                      System.out.println(
          "IOException 被拋出!");
                  }
                  
          finally
                  {
                      closeSocket(socket1);
                      closeSocket(socket2);
                      closeSocket(socket3);
                      closeSocket(socket4);
                  }
              }
          }

          在上面代碼中的最后通過(guò)finally關(guān)閉了被打開的Socket連接,這是一個(gè)好習(xí)慣。因?yàn)橹挥性趯㈥P(guān)閉Socket連接的代碼寫在finally里,無(wú)論是否出錯(cuò),都會(huì)執(zhí)行這些代碼。但要注意,在關(guān)閉Socket連接之前,必須檢查Socket對(duì)象是否為null,這是因?yàn)殄e(cuò)誤很可能在建立連接時(shí)發(fā)生,這樣Socket對(duì)象就沒有建立成功,也就用不著關(guān)閉了。

          1.       手動(dòng)綁定IP

          當(dāng)本機(jī)有多個(gè)IP時(shí)(這些IP可能是多塊網(wǎng)卡上的,也可能是一塊網(wǎng)卡上綁定的多個(gè)IP),在連接服務(wù)器時(shí)需要由客戶端確定需要使用哪個(gè)IP。這樣就必須使用Socket類的另外兩個(gè)構(gòu)方法來(lái)處理。下面讓我們來(lái)看看這兩個(gè)構(gòu)造方法是如何來(lái)使用特定的IP來(lái)連接服務(wù)器的。

          public Socket(String host, int port, InetAddress inetaddress, int localPort)

          這個(gè)構(gòu)造方法的參數(shù)分為兩部分,第一部分為前兩個(gè)參數(shù):hostport,它們分別表示要連接的服務(wù)器的IP和端口號(hào)。第二部分為后兩個(gè)參數(shù):inetaddresslocalPort。其中inetaddress則表示要使用的本地的IP,而localPort則表示要綁定的本地端口號(hào)。這個(gè)localPort這以設(shè)置為本機(jī)的任何未被綁定的端口號(hào)。如果將localPort的值設(shè)為0java將在102465,535之間隨即選擇一個(gè)未綁定的端口號(hào)。因此,在一般情況下將localPort設(shè)為0

          public Socket(InetAddress inetaddress, int port, InetAddress inetaddress1, int localPort)

          這個(gè)構(gòu)造方法和第一個(gè)構(gòu)造方法基本相同,只是將第一個(gè)參數(shù)host換成了inetaddress。其它的使用方法和第一個(gè)構(gòu)造方法類似。

          下面的代碼中將使用這兩個(gè)構(gòu)造方法來(lái)做一個(gè)實(shí)驗(yàn)。我們假設(shè)有兩臺(tái)計(jì)算機(jī):PC1PC2PC1PC2各有一塊網(wǎng)卡。PC1綁定有兩個(gè)IP192.168.18.252200.200.200.200PC2綁定有一個(gè)IP200.200.200.4PC1PC2的子網(wǎng)掩碼都是255.255.255.0。而PC1的默認(rèn)網(wǎng)關(guān)為:192.168.28.254。下面的代碼需要在PC1上運(yùn)行。

          package mysocket;

          import java.net.*;

          public class MoreConnection1
          {
              
          public static void main(String[] args)
              {
                  
          try
                  {
                      InetAddress localAddress1 
          = InetAddress.getByName("200.200.200.200");
                      InetAddress localAddress2 
          = InetAddress.getByName("192.168.18.252");
                      // 如果將localAddress1改成localAddress2,socket1無(wú)法連接成功
                      Socket socket1 = new Socket("200.200.200.4"80, localAddress1, 0);
                      System.out.println(
          "socket1連接成功!");
                      Socket socket2 
          = new Socket("www.ptpress.com.cn"80, localAddress2, 0);
                      System.out.println(
          "socket2連接成功!");
                      
          // 下面的語(yǔ)句將拋出一個(gè)IOException錯(cuò)誤
                      Socket socket3 = new Socket("www.ptpress.com.cn"80, localAddress1, 0);
                      System.out.println(
          "socket3連接成功!");
                      socket1.close();
                      socket2.close();
                      socket3.close();
                  }
                  
          catch (Exception e)
                  {
                      System.out.println(e.getMessage());
                  }
              }
          }

          運(yùn)行上面代碼的輸出結(jié)果如下:

          socket1連接成功!
          socket2連接成功
          !
          Connection timed out: connect

          從上面的輸出結(jié)果可以看出socket1socket2已經(jīng)連接成功socket3并未連接成功。從例程4-8可以看出,socket1在連接時(shí)使用localAddress1綁定到了200.200.200.200上,而PC2IP200.200.200.4,因此,socket1所使用的IPPC2IP在同一個(gè)網(wǎng)段,所以socket1可以連接成功。如果將localAddress1改成localAddress2后,socket1將無(wú)法連接成功。另外兩個(gè)Socket連接socket2socket3是通過(guò)Internet連接www.ptpress.com.cn。它們所不同的是socket2綁定的是192.168.18.252,而socket3綁定的是200.200.200.200。它們執(zhí)行的結(jié)果是socket2可以連接成功,而socket3連接失敗。這是因?yàn)?/span>socket2所綁定的IPPC1的默認(rèn)網(wǎng)關(guān)192.168.18.254在同一個(gè)網(wǎng)段,因此,socket2可以連接到Internet。而socket3所綁定的IPPC1IP不在同一個(gè)網(wǎng)段,因此,socket3將無(wú)法連接到Internet

          二、通過(guò)connect方法連接服務(wù)器

          Socket類不僅可以通過(guò)構(gòu)造方法直接連接服務(wù)器,而且還可以建立未連接的Socket對(duì)象,并通過(guò)connect方法來(lái)連接服務(wù)器。Socket類的connect方法有兩個(gè)重載形式:

          1. public void connect(SocketAddress endpoint) throws IOException

          Socket類的connect方法和它的構(gòu)造方法在描述服務(wù)器信息IP和端口上有一些差異。在connect方法中并未象構(gòu)造方法中以字符串形式的host和整數(shù)形式的port作為參數(shù),而是直接將IP和端口封裝在了SocketAddress類的子類InetSocketAddress中。可按如下形式使用這個(gè)connect方法:

          Socket socket = new Socket();
          socket.connect(
          new InetSocketAddress(host, port));

          2.  public void connect(SocketAddress endpoint, int timeout) throws IOException

              這個(gè)connect方法和第一個(gè)connect類似,只是多了一個(gè)timeout參數(shù)。這個(gè)參數(shù)表示連接的超時(shí)時(shí)間,單位是毫秒。使用timeout設(shè)為0,則使用默認(rèn)的超時(shí)時(shí)間。

          在使用Socket類的構(gòu)造方法連接服務(wù)器時(shí)可以直接通過(guò)構(gòu)造方法綁定本地IP,而connect方法可以通過(guò)Socket類的bind方法來(lái)綁定本地IP。例程4-9演示如何使用connect方法和bind方法。

          package mysocket;

          import java.net.*;

          public class MoreConnection2
          {
              
          public static void main(String[] args)
              {
                  
          try
                  {
                      Socket socket1 
          = new Socket();
                      Socket socket2 
          = new Socket();
                      Socket socket3 
          = new Socket();
                      socket1.connect(
          new InetSocketAddress("200.200.200.4"80));
                      socket1.close();
                      System.out.println(
          "socket1連接成功!");             
                      
          /*
                         將socket2綁定到192.168.18.252將產(chǎn)生一個(gè)IOException錯(cuò)誤  
                      socket2.bind(new InetSocketAddress("192.168.18.252", 0));
                      
          */
                      socket2.bind(
          new InetSocketAddress("200.200.200.200"0));
                      socket2.connect(
          new InetSocketAddress("200.200.200.4"80));
                       
                      socket2.close();
                      System.out.println(
          "socket2連接成功!");

                      socket3.bind(
          new InetSocketAddress("192.168.18.252"0));
                      socket3.connect(
          new InetSocketAddress("200.200.200.4"80), 2000);            
                      socket3.close();
                      System.out.println(
          "socket3連接成功!");
                  }
                  
          catch (Exception e)
                  {
                      System.out.println(e.getMessage());
                  }
              }
          }

          上面的代碼的輸出結(jié)果為:


          socket1連接成功!
          socket2連接成功
          !
          Connection timed out: connect

          在上面代碼中的socket3連接服務(wù)器時(shí)為其設(shè)置了超時(shí)時(shí)間(2000毫秒),因此,socket3在非常短的時(shí)間就拋出了IOException錯(cuò)誤。

          下一篇:
          Java網(wǎng)絡(luò)編程從入門到精通(15):為什么要使用SocketAddress來(lái)管理網(wǎng)絡(luò)地址





          Android開發(fā)完全講義(第2版)(本書版權(quán)已輸出到臺(tái)灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2009-05-18 09:01 銀河使者 閱讀(4220) 評(píng)論(2)  編輯  收藏 所屬分類: java 原創(chuàng)網(wǎng)絡(luò)編程

          評(píng)論

          # re: Java網(wǎng)絡(luò)編程從入門到精通(14):多種多樣的連接數(shù)據(jù)庫(kù)的方式  回復(fù)  更多評(píng)論   

          好像和數(shù)據(jù)庫(kù)沒關(guān)系啊,題目打錯(cuò)了吧
          2009-05-18 17:14 | lveyo

          # re: Java網(wǎng)絡(luò)編程從入門到精通(14):多種多樣的建立網(wǎng)絡(luò)連接的方式  回復(fù)  更多評(píng)論   

          是的,題目打錯(cuò)了,改過(guò)來(lái)了,哈哈,想寫網(wǎng)絡(luò),不知怎么著寫成數(shù)據(jù)庫(kù)了。暈
          2009-05-18 17:17 | 銀河使者
          主站蜘蛛池模板: 原平市| 阿勒泰市| 龙江县| 苗栗县| 兴海县| 称多县| 叙永县| 甘孜| 峨眉山市| 呼伦贝尔市| 普陀区| 宁都县| 大余县| 梁平县| 南丹县| 广南县| 高要市| 钟山县| 古田县| 司法| 武强县| 吉木萨尔县| 花莲市| 吴桥县| 临泽县| 兴山县| 政和县| 金昌市| 福州市| 新平| 旌德县| 拉孜县| 鄂托克旗| 志丹县| 勃利县| 象山县| 宜春市| 沾化县| 天全县| 富宁县| 马关县|