一、简介
在本教程中, 我们将重点讨论Java 套接字编程的超时异常 。我们的目标是了解为什么会发生这些异常以及如何处理它们。
2. Java 套接字和超时
套接字是两个计算机应用程序之间逻辑链接的一个端点 。换句话说,它是应用程序用来通过网络发送和接收数据的逻辑接口。
一般来说,套接字是 IP地址和端口号的组合 。每个套接字都分配有一个特定的端口号,用于标识服务。
基于连接的服务使用基于TCP 的流套接字。为此, Java 提供了 java.net.Socket 类用于客户端编程 。相反, 服务器端 TCP/IP 编程使用 java.net.ServerSocket 类 。
另一种类型的套接字是基于UDP 的数据报套接字,用于无连接服务。 Java 提供了 java.net.DatagramSocket 用于 UDP 操作 。然而,在本教程中,我们将重点关注 TCP/IP 套接字。
3. 连接超时
3.1.什么是“连接超时”?
为了从客户端建立到服务器的连接, 调用套接字构造函数 ,它实例化一个套接字对象。该 构造函数将远程主机地址和端口号作为输入参数 。之后,它尝试根据给定的参数建立与远程主机的连接。
该操作会阻塞所有其他进程,直到成功建立连接 。但是,如果在一段时间后连接未成功,程序将抛出 ConnectionException 并显示“连接超时”消息:
java.net.ConnectException: Connection timed out: connect
在服务器端, ServerSocket 类持续侦听传入的连接请求。 当 ServerSocket 收到连接请求时,它会调用 accept() 方法来实例化一个新的套接字对象 。同样,此方法也会阻塞,直到与远程客户端成功建立连接。
如果 TCP 握手未完成,连接仍然不成功。结果, 程序抛出 IOException ,指示建立新连接时发生错误 。
3.2.为什么会发生?
连接超时错误可能有多种原因:
- 没有服务正在侦听远程主机上的给定端口
- 远程主机不接受任何连接
- 远程主机不可用
- 互联网连接速度慢
- 没有到远程主机的转发路径
3.3.如何处理?
阻塞时间没有限制, 程序员可以为客户端和服务器操作预先设置超时选项 。对于客户端,我们首先创建一个空套接字。之后,我们将使用 connect(SocketAddress endpoint, int timeout) 方法并设置超时参数:
Socket socket = new Socket();
SocketAddress socketAddress = new InetSocketAddress(host, port);
socket.connect(socketAddress, 30000);
超时单位是毫秒 ,并且应该大于0。但是,如果在方法调用返回之前超时到期,则会抛出 SocketTimeoutException :
Exception in thread "main" java.net.SocketTimeoutException: Connect timed out
对于服务器端,我们将使用 setSoTimeout(int timeout) 方法 来设置超时值。 超时 值定义了 ServerSocket.accept() 方法将阻塞的时间:
ServerSocket serverSocket = new new ServerSocket(port);
serverSocket.setSoTimeout(40000);
同样, 超时 单位应该以毫秒为单位,并且应该大于0。如果在方法返回之前超时,它将抛出 SocketTimeoutException 。
有时, 防火墙出于安全原因会阻止某些端口 。因此,当客户端尝试与服务器建立连接时,可能会出现“连接超时”错误。因此, 我们应该在将端口绑定到服务之前检查防火墙设置 ,看看它是否阻止了端口。
4. 读取超时
4.1.什么是“读取超时”?
InputStream 中的 read() 方法调用会阻塞,直到完成从套接字读取数据字节为止。 该操作将等待,直到从套接字读取至少一个数据字节。但是,如果该方法在未指定的时间后没有返回任何内容, 则会抛出 InterrupedIOException 并显示“读取超时”错误消息 :
java.net.SocketTimeoutException: Read timed out
4.2.为什么会发生?
从客户端来看, 如果服务器响应和发送信息的时间较长, 则会发生“读取超时”错误。这可能是由于互联网连接速度慢,或者主机可能处于离线状态。
从服务器端来说,当 服务器读取数据的时间比预设的超时时间长时, 就会发生这种情况。
4.3.如何处理?
对于 TCP 客户端和服务器,我们可以 使用 setSoTimeout(int timeout) 方法 指定 socketInputStream.read() 方法阻塞的时间量 :
Socket socket = new Socket(host, port);
socket.setSoTimeout(30000);
但是,如果在方法返回之前超时已过,程序将抛出 SocketTimeoutException 。
5. 结论
在这篇文章中,我们讨论了Java套接字编程中的超时异常,并学习了如何处理它们。
与往常一样,代码可以 在 GitHub 上获取。