Java网络编程 ServeSocket、Socket 方法 setSoTimeout() 详解
- ServerSocket的setSoTimeout(20000) :
单位为毫秒,用于设置20s内无客户端 Socket 连接,则抛出SocketTimeoutException异常。
- ServerSocket的setSoTimeout(20000)示例代码如下:
//ServerSocketDemo
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class ServerSocketDemo extends Thread {
private ServerSocket serverSocket;
private int i = 1;
public ServerSocketDemo(int port) throws IOException {
serverSocket = new ServerSocket(port);
//设置20s内无客户端连接,则抛出SocketTimeoutException异常
serverSocket.setSoTimeout(20000);
}
public void run(){
while(true) {
System.out.println("服务端第"+i+"次启动中...对应的端口号为:"+ serverSocket.getLocalPort());
i++;
try {
Socket server = serverSocket.accept();
//当服务端监听到客户端的连接后才会执行以下代码
System.out.println("服务端打印的远程主机地址为:"+server.getRemoteSocketAddress());
//监听来自客户端的消息
DataInputStream dis = new DataInputStream(server.getInputStream());
System.out.println("服务端接收到的来自于客户端的信息为:"+dis.readUTF());
//通过socket向客户端发送信息
DataOutputStream dos = new DataOutputStream(server.getOutputStream());
dos.writeUTF("我是服务端,您已连接到:"+server.getLocalSocketAddress());
server.close();
}catch (SocketTimeoutException e){
System.out.println("20s内无客户端连接,正在关闭服务端监听服务");
continue;
}catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
try {
Thread t1 = new ServerSocketDemo(8089);
t1.run();
}catch(IOException e){
e.printStackTrace();
return;
}
}
}
//ClientSocketDemo
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.SocketHandler;
public class ClientSocketDemo {
public static void main(String[] args) {
String serverName = "localhost";
int port = 8089;
try {
Socket client = new Socket(serverName, port);
//当客户端连接到服务端后,才会执行以下代码
System.out.println("客户端已连接到远程主机地址:"+client.getRemoteSocketAddress());
//向服务端发送消息
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("服务端你好,我是客户端,我的地址是: "+client.getLocalSocketAddress());
//接收来自服务端的消息
DataInputStream dis = new DataInputStream(client.getInputStream());
System.out.println("来自于服务端的消息:"+dis.readUTF());
client.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
- 两个类的执行结果如下:
//ServerSocketDemo
服务端第1次启动中...对应的端口号为:8089
服务端打印的远程主机地址为:/127.0.0.1:62770
服务端接收到的来自于客户端的信息为:服务端你好,我是客户端,我的地址是: /127.0.0.1:62770
服务端第2次启动中...对应的端口号为:8089
20s内无客户端连接,正在关闭服务端监听服务
服务端第3次启动中...对应的端口号为:8089
20s内无客户端连接,正在关闭服务端监听服务
//ClientSocketDemo
客户端已连接到远程主机地址:localhost/127.0.0.1:8089
来自于服务端的消息:我是服务端,您已连接到:/127.0.0.1:8089
Process finished with exit code 0
- Socket的setSoTimeout(5) :
public void setSoTimeout(int timeout) throws SocketException
//启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位。将此选项设为非零的超时值时,在与此 Socket 关联的 InputStream 上调用 read() 将只阻塞此时间长度。
//如果超过超时值,将引发 java.net.SocketTimeoutException,虽然 Socket 仍旧有效。选项必须在进入阻塞操作前被启用才能生效。
//超时值必须是 > 0 的数。超时值为 0 被解释为无穷大超时值。
//参数
//timeout - 指定的以毫秒为单位的超时值。
//抛出:
//SocketException - 如果底层协议出现错误,例如 TCP 错误。
- 简单来说就是Socket对象的接收消息的非阻塞实现,注意此方法只是针对read()方法,上述的DataInputStream调用readUTF()方法无效,在固定时间内没有得到结果,就会结束本次阻塞,等待进行下一次的阻塞轮询。也就实现了应用层面的非阻塞。具体含义是指:在5毫秒内,如果没有读取完客户端发送的消息,就会停止读取,并抛出SocketTimeoutException异常。
- 示例代码如下:
//ServerSocketDemo
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
public class ServerSocketDemo extends Thread {
private ServerSocket serverSocket;
private int i = 1;
public ServerSocketDemo(int port) throws IOException {
serverSocket = new ServerSocket(port);
//设置20s内无客户端连接,则抛出SocketTimeoutException异常
serverSocket.setSoTimeout(20000);
}
public void run(){
while(true) {
System.out.println("服务端第"+i+"次启动中...对应的端口号为:"+ serverSocket.getLocalPort());
i++;
try {
Socket server = serverSocket.accept();
// 接收消息非阻塞实现。
// 注意此方法只是针对read()方法,下方的DataInputStream调用readUTF()方法无效
// 方法设置超时时间,在固定时间内没有得到结果,就会结束本次阻塞,等待进行下一次的阻塞轮询。也就实现了应用层面的非阻塞。
// 具体含义是指:在5毫秒内,如果没有读取完客户端发送的消息时,就会停止读取,并抛出SocketTimeoutException异常
server.setSoTimeout(5);
//当服务端监听到客户端的连接后才会执行以下代码
System.out.println("服务端打印的远程主机地址为:"+server.getRemoteSocketAddress());
/*
* server.setSoTimeout(5);起作用是在以下代码的情况下inputStream调用read()方法时才起作用。
* */
InputStream inputStream = server.getInputStream();
byte[] bytes = new byte[1024];
while ((inputStream.read(bytes))!=-1){
System.out.println("在5ms内读取的内容有:"+bytes.toString());
}
//以下代码不会执行,因为5ms内读取不完客户端发送的消息,会产生SocketTimeoutException异常,接着进入下一次阻塞轮询
//通过socket向客户端发送信息
DataOutputStream dos = new DataOutputStream(server.getOutputStream());
dos.writeUTF("我是服务端,您已连接到:"+server.getLocalSocketAddress());
server.close();
}catch (SocketTimeoutException e){
System.out.println("5ms内未读取完客户端的信息,正在关闭服务端监听服务");
continue;
}catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public static void main(String[] args) {
try {
Thread t1 = new ServerSocketDemo(8089);
t1.run();
}catch(IOException e){
e.printStackTrace();
return;
}
}
}
//ClientSocketDemo
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.logging.SocketHandler;
public class ClientSocketDemo {
public static void main(String[] args) {
String serverName = "localhost";
int port = 8089;
try {
Socket client = new Socket(serverName, port);
//当客户端连接到服务端后,才会执行以下代码
System.out.println("客户端已连接到远程主机地址:"+client.getRemoteSocketAddress());
//向服务端发送消息
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF("服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n服务端你好,我是客户端\n123123"+
"我的地址是: "+client.getLocalSocketAddress());
//接收来自服务端的消息
DataInputStream dis = new DataInputStream(client.getInputStream());
System.out.println("来自于服务端的消息:"+dis.readUTF());
client.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
- 两个类的执行结果如下:
//ServerSocketDemo
服务端第1次启动中...对应的端口号为:8089
服务端打印的远程主机地址为:/127.0.0.1:63446
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
在5ms内读取的内容有:[B@4a574795
5ms内未读取完客户端的信息,正在关闭服务端监听服务
服务端第2次启动中...对应的端口号为:8089
//ClientSocketDemo
客户端已连接到远程主机地址:localhost/127.0.0.1:8089
//同时客户端也处于阻塞状态,不会关闭应用进程。因为客户端在等待服务端返回消息
Process finished with exit code 0
- 注:为什么 dos.writeUTF() 方法传递了这么长的字符串?
为了让服务端在 5ms 内读取不完,从而触发 SocketTimeoutException 异常。