在上一篇文章中我们讨论了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)
这是最常用的构造方法,在前面的例子中就是使用的这个构造方法。在使用时只需要提供一个字符串类型的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对象就没有建立成功,也就用不着关闭了。