在NIO网络编程中,需要使用如下语句来完成客户端对服务器的连接:
Selector selector = Selector.open();
InetSocketAddress isa = new InetSocketAddress(host, port);
// 调用open静态方法创建连接到指定主机的SocketChannel
SocketChannel sc = SocketChannel.open(isa);
但却没有相关方法来设置超时参数,这就导致在调用open()方法时,如果连接不上服务器,那么此方法就会长时间阻塞(试了一下,大约阻塞了1-2分钟才抛出SocketTimeoutException),为了解决这个问题,我们可以在调用open()方法前,启动一个定时器,这个定时器会在指定的时间内检查是否已连接成功,这个指定的时间也就是我们希望设置的连接超时时间,当检查已连接上服务器时,提示用户已连接成功;若没有连接上,可在代码中抛出SocketTimeoutException,并提示用户连接超时。代码如下:
package com.test.thread;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketTimeoutException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.Timer;
import java.util.TimerTask;
import android.os.Handler;
import android.os.Message;
public class NetworkNIOThread implements Runnable
{
// 定义处理编码和解码的字符集
public static final Charset CHAR_SET = Charset.forName("GBK");
// 定义检测SocketChannel的Selector对象
private Selector selector;
// 客户端SocketChannel
private SocketChannel sc;
private Handler handler;
private String host;
private int port;
public NetworkNIOThread(Handler handler, String host, int port)
throws IOException
{
this.handler = handler;
this.host = host;
this.port = port;
}
@Override
public void run()
{
connect();
}
public void connect()
{
try
{
selector = Selector.open();
InetSocketAddress isa = new InetSocketAddress(host, port);
//10秒连接超时
new Timer().schedule(tt, 10000);
// 调用open静态方法创建连接到指定主机的SocketChannel
sc = SocketChannel.open(isa);
// 设置该sc以非阻塞方式工作
sc.configureBlocking(false);
// 将Socketchannel对象注册到指定Selector
sc.register(selector, SelectionKey.OP_READ);
Message msg = new Message();
msg.what = 0;
msg.obj = sc;
handler.sendMessage(msg); // 连接成功
new Thread(new NIOReceiveThread(selector, handler)).start();
}
catch (IOException e)
{
e.printStackTrace();
handler.sendEmptyMessage(-1); // IO异常
}
}
TimerTask tt = new TimerTask()
{
@Override
public void run()
{
if (sc == null || !sc.isConnected())
{
try
{
throw new SocketTimeoutException("连接超时");
}
catch (SocketTimeoutException e)
{
e.printStackTrace();
handler.sendEmptyMessage(-6); // 连接超时
}
}
}
};
}