Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 368|回复: 0

[网络编程学习]Java网络编程从入门到精通(14)多种建立网络连接的方式

[复制链接]
  • TA的每日心情
    开心
    2021-3-12 23:18
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2014-11-5 00:03:48 | 显示全部楼层 |阅读模式
    在上一篇文章中我们讨论了Socket
        类的基本用法,并给出的例子中使用Socket
        类连接服务器时使用了一种最简单的连接方式,也就是通过IP
        和端口号来连接服务器。而为了使连接服务器的方式更灵活,Socket
        类不仅可以通过自身的构造方法连接服务器,而且也可以通过connect
        方法来连接数据库
       
       
       
    一、

        通过构造方法连接服务器
       
       
            我们
        可以通过6
        个重载构造函数以不同的方式来连接服务器。这6
        个重载的构造函数可以分为两类:

    1.
        自动选择IP
       

       
         这种方式是最常用的。所谓自动选择IP
        ,是指当本机有多块网卡或者在一个网卡上绑定了多个IP
        时,Socket
        类会自动为我们选择一个可用的IP
        。在上述6
        个构造方法中有4
        个是使用这种方法来连接服务器的。
         
      
       
       
         
       

         
       
      



      public Socket(String host, int port)
       
      

      这是最常用的构造方法,在前面的例子中就是使用的这个构造方法。在使用时只需要提供一个字符串类型的
      IP
      或域名以及一个整型的端口号即可。在这个
      构造方法中可能会抛出两个错误:
      UnknownHostException
      和
      IOException
      。发生第一个错误的原因是我们提供的
      host
      并不存在或不合法,而其它的错误被归为
      IO
      错误。因此,这个构造方法的完整定义是:
       
       
      
      
       
      public
       Socket(String host,
      int
       port)
      throws
       UnknownHostException, IOException
      
      

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

      这个构造方法和第一种构造方法类似
      ,
      只是将字符串形式的
      host
      改为
      InetAddress
      对象类型了。在这个构造方法中之所以要使用
      InetAddress
      类主要是因为考虑到在程序中可能需要使用
      Socket
      类多次连接同一个
      IP
      或域名,这样使用
      InetAddress
      类的效率比较高。另外,在使用字符串类型的
      host
      连接服务器时,可能会发生两个错误,但使用
      InetAddress
      对象来描述
      host
      ,只会发生
      IOException
      错误,这是因为当你将
      IP
      或域名传给
      InetAddress
      时,
      InetAddress
      会自动检查这个
      IP
      或域名,如果这个
      IP
      或域名无效,那么
      InetAddress
      就会抛出
      UnknownHostException
      错误,而不会由
      Socket
      类的构造方法抛出。因此,这个构造方法的完整定义是:

      
      
       
      public
       Socket(InetAddress inetaddress,
      int
       port)
      throws
       IOException
      
      

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

      这个构造方法和第一种构造方法差不多,只是多了一个boolean
      类型的stream
      参数。如果这个stream
      为true
      ,那么这个构造方法和第一种构造方法完全一样。如果stream
      为false
      ,则使用UDP
      协议建立一个UDP
      连接(UDP
      将在下面的章节详细讨论,在这里只要知道它和TCP
      最大的区别是UDP
      是面向无连接的,而TCP
      是面向有连接的),也许是当初Sun
      的开发人员在编写Socket
      类时还未考虑编写处理UDP
      连接的DatagramSocket
      类,所以才将建立UDP
      连接的功能加入到Socket
      类中,不过Sun
      在后来的JDK
      中加入了DatagramSocket
      类,所以,这个构造方法就没什么用了,因此,Sun
      将其设为了Deprecated
      标记,也就是说,这个构造方法在以后的JDK
      版本中可以会被删除。其于以上原因,在使用java
      编写网络程序时,尽量不要使用这个构造方法来建立UDP
      连接。


      

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

      这个构造方法和第三种构造方法的
      flag
      标记的含义一样,也是不建议使用的。

         下面的代码演示
      上述
      4
      种构造方法的使用:
      

       
       
      
      
       
      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错误
                
      //
       测试public Socket(String host, int port)
      

                  socket1
      =
       
      new
       Socket(
      "
      www.ptpress.com.cn
      "
      ,
      80
      );
                 System.out.println(
      "
      socket1连接成功!
      "
      );
                
      //
       测试public Socket(InetAddress inetaddress, int port)
      

                  socket2
      =
       
      new
       Socket(InetAddress.getByName(
      "
      www.ptpress.com.cn
      "
      ),
      80
      );
                 System.out.println(
      "
      socket2连接成功!
      "
      );

                
      //
       下面的两种建立连接的方式并不建议使用
                
      //
       测试public Socket(String host, int port, boolean stream)
      

                  socket3
      =
       
      new
       Socket(
      "
      www.ptpress.com.cn
      "
      ,
      80
      ,
      false
      );
                 System.out.println(
      "
      socket3连接成功!
      "
      );
                
      //
       测试public Socket(InetAddress inetaddress, int i, boolean flag)
      

                  socket4
      =
       
      new
       Socket(InetAddress.getByName(
      "
      www.ptpress.com.cn
      "
      ),
      80
      ,
      false
      );
                 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);
             }
         }
    }

      
      

      在上面代码中
      的最后通过finally
      关闭了被打开的Socket
      连接,这是一个好习惯。因为只有在将关闭Socket
      连接的代码写在finally
      里,无论是否出错,都会执行这些代码。但要注意,在关闭Socket
      连接之前,必须检查Socket
      对象是否为null
      ,这是因为错误很可能在建立连接时发生,这样Socket
      对象就没有建立成功,也就用不着关闭了。

      

      1.      
      手动绑定
      IP
      

      当本机有多个IP
      时(这些IP
      可能是多块网卡上的,也可能是一块网卡上绑定的多个IP
      ),
      在连接服务器时需要由客户端确定需要使用哪个IP
      。这样就必须使用Socket
      类的另外两个构方法来处理。下面让我们来看看这两个构造方法是如何来使用特定的IP
      来连接服务器的。
      

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

      这个构造方法的参数分为两部分,第一部分为前两个参数:
      host
      和
      port
      ,它们分别表示要连接的服务器的
      IP
      和端口号。第二部分为后两个参数:
      inetaddress
      和
      localPort
      。其中
      inetaddress
      则表示要使用的本地的
      IP
      ,而
      localPort
      则表示要绑定的本地端口号。这个
      localPort
      可以设置为本机的任何未被绑定的端口号。如果将
      localPort
      的值设为
      0
      ,
      java
      将在
      1024
      到
      65,535
      之间随即选择一个未绑定的端口号。因此,在一般情况下将
      localPort
      设为
      0
      。
      

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

      这个构造方法和第一个构造方法基本相同,只是将第一个参数
      host
      换成了
      inetaddress
      。其它的使用方法和第一个构造方法类似。
      

      在
      下面的代码
      中将使用这两个构造方法来做一个实验。我们假设有两台计算机:
      PC1
      和
      PC2
      。
      PC1
      和
      PC2
      各有一块网卡。
      PC1
      绑定有两个
      IP
      :
      192.168.18.252
      和
      200.200.200.200
      。
      PC2
      绑定有一个
      IP
      :
      200.200.200.4
      。
      PC1
      和
      PC2
      的子网掩码都是
      255.255.255.0
      。而
      PC1
      的默认网关为:
      192.168.28.254
      。下面的代码
      需要在
      PC1
      上运行。


      
      
       
      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无法连接成功
      

                  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连接成功!
      "
      );
                
      //
       下面的语句将抛出一个IOException错误
      

                  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());
             }
         }
    }

      
      

      运行上面代码
      的输出结果如下:
      
      
       
      socket1连接成功
      !
      
    socket2连接成功
      !
      
    Connection timed out: connect

      

      从上面的输出结果可以看出
      ,
      socket1
      和
      socket2
      已经连接成功
      ,
      而
      socket3
      并未连接成功。从例程
      4-8
      可以看出,
      socket1
      在连接时使用
      localAddress1
      绑定到了
      200.200.200.200
      上,而
      PC2
      的
      IP
      是
      200.200.200.4
      ,因此,
      socket1
      所使用的
      IP
      和
      PC2
      的
      IP
      在同一个网段,所以
      socket1
      可以连接成功。如果将
      localAddress1
      改成
      localAddress2
      后,
      socket1
      将无法连接成功。另外两个
      Socket
      连接
      socket2
      和
      socket3
      是通过
      Internet
      连接
      www.ptpress.com.cn
      。它们所不同的是
      socket2
      绑定的是
      192.168.18.252
      ,而
      socket3
      绑定的是
      200.200.200.200
      。它们执行的结果是
      socket2
      可以连接成功,而
      socket3
      连接失败。这是因为
      socket2
      所绑定的
      IP
      和
      PC1
      的默认网关
      192.168.18.254
      在同一个网段,因此,
      socket2
      可以连接到
      Internet
      。而
      socket3
      所绑定的
      IP
      和
      PC1
      的
      IP
      不在同一个网段,因此,
      socket3
      将无法连接到
      Internet
      。

      

      
    二、

      通过
      connect
      方法连接服务器
      

      Socket
      类不仅可以通过构造方法直接连接服务器,而且还可以建立未连接的
      Socket
      对象,并通过
      connect
      方法来连接服务器。
      Socket
      类的
      connect
      方法有两个重载形式:
      

      1. public void connect(SocketAddress endpoint) throws IOException
      

      Socket
      类的
      connect
      方法和它的构造方法在描述服务器信息
      (
      IP
      和端口
      )
      上有一些差异。在
      connect
      方法中并未象构造方法中以字符串形式的
      host
      和整数形式的
      port
      作为参数,而是直接将
      IP
      和端口封装在了
      SocketAddress
      类的子类
      InetSocketAddress
      中。可按如下形式使用这个
      connect
      方法:
      
      
       
      Socket socket
      =
       
      new
       Socket();
    socket.connect(
      new
       InetSocketAddress(host, port));

      

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

          
      这个
      connect
      方法和第一个
      connect
      类似,只是多了一个
      timeout
      参数。这个参数表示连接的超时时间,单位是毫秒。使用
      timeout
      设为
      0
      ,则使用默认的超时时间。
      

      在使用
      Socket
      类的构造方法连接服务器时可以直接通过构造方法绑定本地
      IP
      ,而
      connect
      方法可以通过
      Socket
      类的
      bind
      方法来绑定本地
      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将产生一个IOException错误  
                 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());
             }
         }
    }

      
      

      上面的代码
      的输出结果为:
      


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

      

      在上面代码
      中的socket3
      连接服务器时为其设置了超时时间(2000
      毫秒),因此,socket3
      在非常短的时间就抛出了IOException
      错误。
      

       
      
    本文出自 “软件改变整个宇宙” 博客,请务必保留此出处http://androidguy.blog.51cto.com/974126/214451



      
      
       
       

         
       

         
       
      
    复制代码

    源码下载:http://file.javaxxz.com/2014/11/5/000348500.zip
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-25 13:47 , Processed in 0.304341 second(s), 36 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表