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

2/22/2017来源:ASP.NET技巧人气:1525

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分钟,既没有连接成功,也没有抛出异常,那么会抛出SocketTimeoutExceptionsocket. 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 扫描二维码关注:这里写图片描述