在上一篇文章中我们讨论了Socket类的基本用法,并给出的例子中使用Socket类连接服务器时使用了一种最简单的连接方式,也就是通过IP和端口号来连接服务器。而为了使连接服务器的方式更灵活,Socket类不仅可以通过自身的构造方法连接服务器,而且也可以通过connect方法来连接数据库。
一、通过构造方法连接服务器
    我们可以通过6个重载构造函数以不同的方式来连接服务器。这6个重载的构造函数可以分为两类:

1. 自动选择IP

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

<!--[if !supportLists]-->(1)    <!--[endif]-->public Socket(String host, int port) <?XML:NAMESPACE PREFIX = O />
这是最常用的构造方法,在前面的例子中就是使用的这个构造方法。在使用时只需要提供一个字符串类型的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错误。
 
 
 
国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

Java网络编程从入门到精通(14):多种多样的建立网络连接的方式相关推荐

  1. java消息头,Java网络编程从入门到精通:HTTP消息头字段

    Java网络编程从入门到精通:HTTP消息头字段 一.通用头字段 1. Connection 这个字段只在HTTP1.1协议中存在.它决定了客户端和服务器进行了一次会话后, 服务器是否立即关闭网络连接 ...

  2. ASP网络编程从入门到精通 下载

    <ASP网络编程从入门到精通> 清华大学出版社 特点: 面向ASP零基础读者,循序渐进 全面分析ASP技术细节 用代码描述个个知识点,操作性强 通过典型模块设计,体会ASP的奥妙 通过网上 ...

  3. Java网络编程从入门到精通(24):实现HTTP断点续传下载工具(附源代码)

    源代码下载:download.rar 在前面的文章曾讨论了HTTP消息头的三个和断点继传有关的字段.一个是请求消息的字段Range,另两个是响应消息字段Accept-Ranges和Content-Ra ...

  4. 《 Java并发编程从入门到精通》Thread安全与不安全

    作者:张振华    购买链接:天猫商城  JD商城  当当书店 鸟欲高飞先振翅,人求上进先读书.本文是原书的第3章  Thread安全3.2 什么是不线程安全.3.3什么是线程不安全. 3.2 什么是 ...

  5. Java网络编程从入门到精通(1):Internet地址概述

    所有连入Internet的终端设备(包括计算机.PDA.打印机以及其他的电子设备)都有一个唯一的索引,这个索引被称为IP地址.现在Internet上的IP地址大多由四个字节组成,这种IP地址叫做IPv ...

  6. Java网络编程从入门到精通(25):创建ServerSocket对象

    ServerSocket类的构造方法有四种重载形式,它们的定义如下: public ServerSocket() throws IOException public ServerSocket(int  ...

  7. Java网络编程从入门到精通 (9):使用isXxx方法判断地址类型

     IP地址分为普通地址和特殊地址.在前面的文章中所使用的大多数都是普通的IP地址,在本文中将介绍如何利用InetAddress类提供的十个方法来确定一个IP地址是否是一个特殊的IP地址. 一.isAn ...

  8. Java网络编程从入门到精通(4):DNS缓存

    在通过DNS查找域名的过程中,可能会经过多台中间DNS服务器才能找到指定的域名,因此,在DNS服务器上查找域名是非常昂贵的操作.在Java中为了缓解这个问题,提供了DNS缓存.当InetAddress ...

  9. Java网络编程从入门到精通(2):创建InetAddress对象的四个静态方法

    InetAddress类是Java中用于描述IP地址的类.它在java.net包中.在Java中分别用Inet4Address和Inet6Address类来描述IPv4和IPv6的地址.这两个类都是I ...

最新文章

  1. node:ORM、数据模型、脚本创建模型与服务层
  2. Jenkins:部署JEE工件
  3. mysql 子表 关联查询语句_MySQL-基本查询语句及方法,连表和子查询
  4. 虚拟机中安装vmware tools 到 Debian 时出现 找不到kernel headers的提示
  5. 给iOS开发新手送点福利,简述UIPageControl的属性和用法
  6. 深度linux运行浏览器中毒,使用深度Deepin系统的用户可在商店中安装360安全浏览器正式版...
  7. 去除winrar广告
  8. qt设置进程开机自启动
  9. oracle rac 成本及架构,Oracle Extended RAC 架构实战
  10. linux下delete释放不了内存,c++delete后虚拟内存不降的原因(疑似内存泄漏)
  11. 计算机七进制乘法,编程达人
  12. JDK8新特性Stream流使用详解
  13. 【转】Foobar 2000设置replay gain
  14. 计算机科学方面的学术会议
  15. 程序人生--2010年(60)
  16. 微信公众平台注册十大常见问题(公众号篇)
  17. 一沙一世界,一花一天堂
  18. Python spider (二) Requests Lxml bs4
  19. [COI2007] Sabor
  20. Java向上取整与向下取整

热门文章

  1. html学习文档-3、HTML元素
  2. 把报表的数据导出Excel
  3. 2013应届毕业生“京北方”校招应聘总结
  4. NIO:与 Buffer 一起使用 Channel
  5. linux 硬链接和软链接
  6. 大家一起学面向对象设计模式系列Chapter 02 软件设计的基本原则
  7. Linux下的各种文件阅读器
  8. js:封装获取当前元素的所有的哥哥元素节点
  9. C# 3.0下有限状态机的一种优雅的实现
  10. 解决PLSQL Developer 9连接oracle10g出现乱码