您的位置:首页 > 理论基础 > 计算机网络

Java网络编程由浅入深二 Socket的构造和连接服务端的相关异常

2017-02-20 15:46 661 查看

Socket构造方法和Socket的设置与异常

本文将介绍Socket的构造方法和Socket的相关属性设置与异常处理

构造Socket

设置等待超时时间

设置服务器地址

设置客户端地址

客户端连接服务器可能出现的异常

构造Socket

Socket的构造方法有如下几种重载方式:

Socket();
Socket(InetAddress address, int port)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
Socket(Proxy proxy)
Socket(SocketImpl impl)
Socket(String host, int port)
Socket(String host, int port, InetAddress localAddr, int localPort)


除了第一个构造器外,其他构造器都会尝试与服务器建立连接,如果连接成功返回Socket对象;如果因为某些原因连接失败,就抛出IOException。

如下代码扫描主机上从1到1024之间的端口,判断这些端口是否已经被服务器程序监听。

public class PortScanner {
public static void main(String[] args) {
String host = "localhost";
new PortScanner().scan(host);
}

public void scan(String host){
Socket socket = null;
for(int i=0;i<1024;i++){
try {
socket = new Socket(host, i);
System.out.println("There is a server on port "+i);
}  catch (IOException e) {
System.out.println("Can't connect to port "+i);
}finally{
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}


设置等待建立连接的超时时间

使用不带参数的构造方法,设置socket连接超时时间:

Socket socket = new Socket();
SocketAddress endPoint = new InetSocketAddress("localhost", 8000);
socket.connect(endPoint, 60000);


以上代码表示用于连接本机上监听的8000端口,等待连接的最长时间为1分钟。如果在1分钟内连接成功,则connect()方法顺利返回;如果在1分钟之内出现异常,则抛出异常;如果超过1分钟,既没有连接成功,也没有抛出异常,那么会抛出
SocketTimeoutException
socket. connect(SocketAddress endpoint, int timeout);
负责连接服务器,参数endpoint指定服务器地址,参数timeout设定超时时间,以毫秒为单位。如果参数timeout为0,表示永远不超时。

设置服务器地址

Socket的构造方法中,除了第一个不带参数的构造方法,其他构造方法都需要指定服务器地址,包括服务器的IP或主机名,以及端口:

Socket(InetAddress address, int port)

Socket(String host, int port)

InetAddress类表示服务器的IP地址,InetAddress提供了很多静态方法:

// 返回本地主机的IP地址
InetAddress.getLocalHost();
// 返回代表10.202.164.65的IP地址
InetAddress.getByName("10.202.164.65");
// 返回域名为'www.csdn.net'的ip地址
InetAddress.getByName("www.csdn.net");


设置客户端的地址:

默认情况下,客户端的IP地址来自于客户端程序所在的主机,客户端的端口则由操作系统随机分配。但是Socket类还是提供了构造方法允许显式地设置客户端的IP和端口:

//参数localAddr和localPort用来设置客户端的IP和端口。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
Socket(String host, int port, InetAddress localAddr, int localPort)


客户端连接服务器可能抛出的异常

当Socket构造方法请求连接服务器时,可能会抛出下面的异常:

• UnknownHostException:如果无法识别主机的名字或IP地址,就会抛出这种异常

• ConnectException:如果没有服务器进程监听指定的端口,或者服务器拒绝连接,就会抛出这种异常。

• SocketTimeoutException:如果等待连接超时,就会抛出这种异常。

• BindException:如果无法把Socket对象与指定的本地IP地址或端口绑定,就会抛出这种异常。

通过下面测试类为例,演示抛出异常的原因。

public class ConnectTester {
public static void main(String[] args) {
String host = "www.csdn.net";
int port = 12312;

new ConnectTester().connect(host, port);
}

public void connect(String host,int port){
SocketAddress remoteAddress = new InetSocketAddress(host, port);
Socket socket = null;
String result = null;
try{
socket = new Socket();
long start = System.currentTimeMillis();
socket.connect(remoteAddress,1000);
long end = System.currentTimeMillis();
result = (end-start)+"ms";
}catch(BindException bindException){
result = "BindException,Socket对象与指定的本地IP地址或端口绑定,异常";
}catch (UnknownHostException unknownHostException) {
result = "UnknownHostException,无法识别的主机";
}catch (ConnectException connectException) {
result = "ConnectException,连接被拒绝";
}catch (SocketTimeoutException socketTimeoutException) {
result = "SocketTimeoutException,连接超时";
}catch(IOException e){
result = "IOException,连接失败";
}finally{
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println(remoteAddress+" : "+result);
}
}


• 抛出UnknownHostException情况:

如果无法识别主机的名字或IP地址,就会抛出这种异常。例如:host为:’ somehost11’。Socket的connect方法就会抛出UnknownHostException异常。

• 抛出ConnectException的情况:

在以下两种情况会抛出ConnectException。

1) 没有服务器进程监听指定的端口。例如:host为 ‘localhost’ port为 12321 。如果本机的12321端口没有被任何进程监听,则Socket连接方法会抛出ConnectException。

2) 服务器进程拒绝连接。介绍服务器进程拒绝客户的连接请求的情形。如下示例代码,一个简单的服务程序ServerSocket构造方法中的第二个参数表示请求队列的长度。如果队列的请求已满,服务器就会拒绝其余的请求。抛出ConnectException

public class SimplServer {
public static void main(String[] args) throws Exception{
ServerSocket serverSocket = new ServerSocket(8888, 2);
Thread.sleep(3600000);
}
}


public class SimpleClient {
public static void main(String[] args) throws Exception{
String host = "localhost";
int port = 8888;
Socket s1 = new Socket(host, port);
System.out.println("第一次连接成功");
Socket s2 = new Socket(host, port);
System.out.println("第二次连接成功");
Socket s3 = new Socket(host, port);
System.out.println("第三次连接成功");
}
}


• 抛出SocketTimeoutException的情形

如果客户端连接超时,就会抛出这种异常。修改
socket.connect(remoteAddress, 1);
由原来的1000毫秒修改为1毫秒,这样增加了超时的可能性。

• 抛出BindException的情形:

将代码

socket = new Socket();
socket.connect(remoteAddress, 1000);


修改为:

socket = new Socket();
socket.bind(new InetSocketAddress(InetAddress.getByName("222.34.5.6"), 5678));
socket.connect(remoteAddress, 1000);


修改后的代码试图把Socket的本地IP地址设为222.34.5.6,把本地端口设置为5678。如果本机不具有该IP,或者端口被占用,那么就会出现BindException。

欢迎关注微信公众号
在路上的coder
每天分享优秀的Java技术文章!

扫描二维码关注:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: