Java套接字的连接超时与读取超时

2023/06/01

1. 概述

在本教程中,我们将重点介绍Java套接字编程的超时异常。我们的目标是了解为什么会出现这些异常,以及如何处理它们。

2. Java套接字和超时

套接字是两个计算机应用程序之间逻辑链接的一个端点。换句话说,它是应用程序用来通过网络发送和接收数据的逻辑接口。

一般来说,套接字是IP地址和端口号的组合。每个套接字都分配有一个用于标识服务的特定端口号。

基于连接的服务使用基于TCP的流套接字。为此,Java提供了用于客户端编程的java.net.Socket类。相反,服务器端TCP/IP编程使用java.net.ServerSocket类

另一种套接字是基于UDP的数据报套接字,用于无连接服务。Java为UDP操作提供了java.net.DatagramSocket。但是,在本教程中,我们将重点关注TCP/IP套接字。

3. 连接超时

3.1 什么是“连接超时”?

为了从客户端建立到服务器的连接,调用了套接字构造函数,它实例化一个套接字对象。构造函数将远程主机地址和端口号作为输入参数。之后,它会尝试根据给定的参数与远程主机建立连接。

该操作会阻塞所有其他进程,直到成功建立连接。但是,如果连接在特定时间后不成功,程序将抛出带有“Connection timed out”消息的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。

有时,出于安全原因,防火墙会阻止某些端口。因此,当客户端尝试与服务器建立连接时,可能会出现“connection timed out”错误。因此,在将端口绑定到服务之前,我们应该检查防火墙设置以查看它是否阻止了端口。

4. 读取超时

4.1 什么是“读取超时”?

InputStream中的read()方法调用会阻塞,直到它完成从套接字中读取数据字节。该操作将一直等待,直到它从套接字读取至少一个数据字节。但是,如果该方法在未指定的时间后未返回任何内容,它会抛出带有“Read timed out”错误消息的InterruptedIOException

java.net.SocketTimeoutException: Read timed out

4.2 为什么会发生?

从客户端来看,如果服务器需要更长的时间来响应和发送信息,就会发生“read timed out”错误。这可能是由于互联网连接速度慢,或者主机可能处于离线状态。

从服务器端来说,当服务器读取数据的时间比预设的超时时间长时,就会发生这种情况

4.3 如何处理?

对于TCP客户端和服务器,我们可以使用setSoTimeout(int timeout)方法指定socketInputStream.read()方法阻塞的时间量

Socket socket = new Socket(host, port);
socket.setSoTimeout(30000);

但是,如果在方法返回之前超时已过,程序将抛出SocketTimeoutException。

5. 总结

在本文中,我们讨论了Java套接字编程中的超时异常,并学习了如何处理它们。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章