问题分析
当服务端创建SocketServer时、客户端向服务端创建socket时、连接过程中发生错误时会抛出此类异常。此类异常主要有四种子类BindException、 ConnectException、NoRouteToHostException、PortUnreachableException,均可以被SocketException捕获。这四种子类的问题分析如下:
BindException试图将套接字绑定到本地地址和端口时发生错误的情况下,抛出此异常。
ConnectException试图将套接字连接到远程地址和端口时发生错误的情况下,抛出此异常,典型的方式是因为远程主机拒绝,例如远程主机不存在或并未监听此端口。
NoRouteToHostException试图将套接字连接到远程地址和端口时发生错误的情况下,抛出此异常,一般原因是因为防火墙拦截或必经路由器中断引起的。
PortUnreachableException在连接的数据报上已接收到ICMP Port Unreachable消息时,抛出该异常。
解决方案
当服务端创建SocketServer时、客户端向服务端创建socket时、连接过程中发生错误时会抛出此类异常,建议使用try catch finally块捕获异常并做好业务处理。
示例一
java.net.SocketException:Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:196)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
问题分析:该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是如果一端的Socket被关闭(或主动关闭或者因为异常退出而引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection reset)。主要原因是在连接断开后的读和写操作引起的异常。
解决方案:建议不要频繁建立过多socket请求导致服务器压力增大抛出SocketException,并使用try catch块捕获异常做后续处理。如果服务是幂等的,则客户端可以重试连接。如果不是幂等的,重试可能造成重复提单。
代码示例:
1:服务端代码
class SimpleServer implements Runnable {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(8111);
serverSocket.setSoTimeout(3000);
while (true) {
try {
Socket clientSocket = serverSocket.accept();
BufferedReader inputReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
System.out.println("Client said :"+ inputReader.readLine());
} catch (SocketTimeoutException e) {
e.printStackTrace();
}
}
}catch (SocketException e) {
e.printStackTrace();
}catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2:客户端代码
class SimpleClient implements Runnable {
@Override
public void run() {
Socket socket = null;
try {
socket = new Socket("localhost", 8111);
PrintWriter outWriter = new PrintWriter(socket.getOutputStream(), true);
System.out.println("Wait");
Thread.sleep(15000);
//throw new Exception("Random exception");
outWriter.println("Hello Mr. Server!");
}catch (SocketException e) {
e.printStackTrace();
}catch (InterruptedException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (socket != null)
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
示例二
java.net.ConnectException:Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(NativeMethod)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:579)
at java.net.Socket.connect(Socket.java:528)
at java.net.Socket.(Socket.java:425)
at java.net.Socket.(Socket.java:208)
问题分析:服务端不能响应客户端的连接请求抛出异常。可能原因:IP或者端口写错、服务器宕机、防火墙等原因。
解决方案:服务端不能响应客户端的连接请求抛出异常。建议检查IP或者端口正确、服务器可以访问、防火墙未限制。代码示例与示例一相同。