Android Socket tcp连接状态判断
Android 实现tcp连接的方式
SocketChannel
AsynchronousSocketChannel
Socket
SocketChannel
-
SocketChannel
是Java NIO库提供的一种通道(Channel)类型,用于基于NIO的网络通信。 -
SocketChannel
提供了非阻塞的I/O操作,可以实现高效的多路复用(Multiplexing)。 -
它是双向通信的,可以通过
read()
和write()
方法进行读取和写入操作。 -
在Android中,可以使用
SocketChannel
来进行网络通信,但需要注意在主线程之外执行,以免阻塞主线程。
select()
方法通常用于服务器端的事件监听,用于监视多个通道的可读、可写等事件状态。对于客户端而言,select()
方法不适合用于连接监听,因为客户端通常只需要与单个服务器建立连接,而不需要同时监听多个连接。
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);//读写模式。false表示非阻塞,true表示阻塞。
/**
* 先注册再连接
*/
mSelector = Selector.open();
socketChannel.register(mSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
socketChannel.connect(new InetSocketAddress(getIp(),getPort()));
int count = mSelector.select();
Log.e(TAG,"count = " + count);
AsynchronousSocketChannel
-
AsynchronousSocketChannel
是Java NIO.2引入的异步I/O库中的一部分,用于异步非阻塞的网络通信。 -
AsynchronousSocketChannel
提供了基于回调(Callback)的异步操作,使得在进行网络通信时可以非阻塞地执行其他任务。 -
它支持读取和写入操作,并提供了
read()
和write()
方法来进行异步操作。
在Android中,可以使用AsynchronousSocketChannel
进行异步的网络通信,适用于需要在进行网络操作时不阻塞主线程的场景。
connect() 连接时判断
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class Client {
public static void main(String[] args) {
try {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("example.com", 8080), null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
// 连接成功
System.out.println("Connected to the server");
// 执行后续操作
}
@Override
public void failed(Throwable exc, Void attachment) {
// 连接失败
System.out.println("Failed to connect to the server");
// 执行失败处理逻辑
}
});
// 可以继续进行其他操作
} catch (IOException e) {
e.printStackTrace();
}
}
}
read()判断实时连接状态
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
public class Client {
private static final int BUFFER_SIZE = 1024;
public static void main(String[] args) {
try {
AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();
channel.connect(new InetSocketAddress("example.com", 8080), null, new CompletionHandler<Void, Void>() {
@Override
public void completed(Void result, Void attachment) {
System.out.println("Connected to the server");
startReading(channel); // 开始读取服务器数据
// 执行其他操作
}
@Override
public void failed(Throwable exc, Void attachment) {
System.out.println("Failed to connect to the server");
}
});
// 阻塞等待连接完成
channel.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
private static void startReading(AsynchronousSocketChannel channel) {
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
channel.read(buffer, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer bytesRead, Void attachment) {
if (bytesRead == -1) {
// 服务器已经关闭了连接
System.out.println("Server disconnected");
// 执行处理断开连接的逻辑
} else {
// 继续读取数据
buffer.flip();
byte[] data = new byte[buffer.remaining()];
buffer.get(data);
String receivedData = new String(data);
System.out.println("Received data from server: " + receivedData);
buffer.clear();
startReading(channel); // 继续读取服务器数据
}
}
@Override
public void failed(Throwable exc, Void attachment) {
// 读取操作失败,可以认为服务器已经断开连接
System.out.println("Failed to read data from server: " + exc.getMessage());
// 执行处理断开连接的逻辑
}
});
}
}
通过不断进行读取操作,客户端可以实时监听到服务器主动断开连接的情况,并执行相应的处理逻辑。
Socket
-
Socket
是Java中经典的Socket类,用于基于传统的阻塞式I/O进行网络通信。 -
它提供了阻塞式的读取和写入操作,即
read()
和write()
方法。 -
在Android中,可以使用
Socket
类进行网络通信,但需要注意在Android的主线程中执行网络操作可能导致阻塞,因此通常建议在子线程中使用Socket
类进行网络通信。
read() = -1
int bytesRead = inputStream.read(buffer);
if (bytesRead == -1) {
// 服务器已经关闭了连接
System.out.println("Server disconnected");
// 执行处理断开连接的逻辑
}
read()是阻塞的,非阻塞模式:将Socket设置为非阻塞模式,可以通过setSoTimeout()
方法设置超时时间,然后使用available()
方法检查是否有数据可读,再调用read()
方法读取数据。
Java NIO(New I/O)中提供了更为灵活的非阻塞I/O操作方式,可以使用Selector
、SelectableChannel
等类来实现非阻塞的Socket通信。
socket.setSoTimeout(timeout); // 设置超时时间
InputStream inputStream = socket.getInputStream();
while (true) {
if (inputStream.available() > 0) {
int bytesRead = inputStream.read(buffer);
// 处理读取的数据
break; // 退出循环
} else {
// 没有数据可读,可以执行其他操作
}
}
当read()
方法返回-1时,并不一定意味着连接已经断开,可能还存在其他情况。
在Socket编程中,当read()
方法返回-1时,表示已经到达流的末尾,即远程服务器已经关闭了连接。这通常是一种常见的情况,可以可靠地判断连接是否已经断开。
还有一些其他情况可能导致read()
方法返回-1:
-
读取超时:如果在设置的超时时间内没有读取到数据,
read()
方法可能会返回-1。这并不表示连接已经断开,而只是表示在超时时间内没有数据可读。这种情况下,您可以根据具体需求来判断是否认为连接已经断开。 -
错误发生:在某些错误情况下,
read()
方法也可能返回-1。例如,网络中断、连接重置等。这时候,read()
方法返回-1可能表示连接已经断开,但也可能是由于其他错误导致的。为了确定连接的状态,您可能需要根据具体的错误类型进行额外的处理和判断。
因此,仅仅依靠read()
方法返回-1是无法绝对确定连接已经断开的,需要结合其他上下文信息和错误处理来判断连接的状态。
上述适合不停读取消息的场景下判断连接状态
心跳机制
1.sendUrgentData()捕获IO异常,(接收端要处理、过滤1字节消息)
try {
mSocket.sendUrgentData(0xFF);
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG,"tcp HeartbeatThread run error = " + e.toString());
}
mOutputStream.write(heartbeatByte);
mOutputStream.flush();
SocketChannel
和AsynchronousSocketChannel
是Java NIO库提供的非阻塞I/O的方式,适用于需要高效、异步的网络通信。而Socket
类是传统的阻塞式I/O的方式,适用于简单的网络通信场景。
本文来自博客园,作者:西瓜皮不甜,转载请注明原文链接:https://www.cnblogs.com/Jieth/p/17439780.html