首页 > 其他分享 >Android Socket tcp连接状态判断

Android Socket tcp连接状态判断

时间:2023-05-29 10:57:58浏览次数:40  
标签:AsynchronousSocketChannel Socket read 阻塞 tcp public Android 连接

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操作方式,可以使用SelectorSelectableChannel等类来实现非阻塞的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:

  1. 读取超时:如果在设置的超时时间内没有读取到数据,read()方法可能会返回-1。这并不表示连接已经断开,而只是表示在超时时间内没有数据可读。这种情况下,您可以根据具体需求来判断是否认为连接已经断开。

  2. 错误发生:在某些错误情况下,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();

SocketChannelAsynchronousSocketChannel是Java NIO库提供的非阻塞I/O的方式,适用于需要高效、异步的网络通信。而Socket类是传统的阻塞式I/O的方式,适用于简单的网络通信场景。

标签:AsynchronousSocketChannel,Socket,read,阻塞,tcp,public,Android,连接
From: https://www.cnblogs.com/Jieth/p/17439780.html

相关文章

  • Socket
    1.IP操作publicclassWeb1{publicstaticvoidmain(String[]args)throwsIOException{try{//查询ipInetAddressia=InetAddress.getByName("www.baidu.com");System.out.println(ia);//本机地址......
  • Android Studio 添加汉化包
    1.查看自己androidstudio软件版本   我的版本为222那么需下载222的汉化包2.点击这里前往下载相应版本的汉化包小版本无需注意,大版本对就可以。我这里选择为 下载后再进行解压3.导入汉化包 选择好下载文件的路径并导入,然后会提示需要重新启动,重启后即可 ......
  • wireshark 结合 go 对每个请求进行 https tls tcp 内容解密
    众所周知,wireshark是一款流行的抓包软件,我们可以很方便地查看每个TCP包的具体信息。对于HTTP协议的数据,还可以查看每个协议层具体信息内容。但是对于HTTPS的数据,我们只能查看IP层以下的数据,TLS及以上的数据都是被加密过的,如下图所示。 在某些特殊的场景下,我们想查......
  • 网易面经:深剖TCP协议的流量控制和拥塞控制,你懂了吗?
    TCP(TransmissionControlProtocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC793定义。TCP提供全双工通信、数据可靠传输和拥塞控制等功能,适用于因特网等应用场景。TCP位于OSI七层协议模型的网络层,与用户数据报协议(UDP)一起构成了传输层协议。T......
  • brpc - Socket::Write
    Socket::Write构建一个WriteRequest,然后调用StartWrite().Socket::StartWrite有一个_write_head成员,每次写入时,会将WriteRequest地址写入这个成员,写入操作会返回旧的req。如果旧的req存在,则req->next=old_req,当前线程直接返回。当前的req会在旧req写完之后被写入。......
  • Android反射的使用
    publicclassMyReflectUtils{privateMyReflectUtils(inti){}publicMyReflectUtils(){}/***三种方式获取Class对象*Class对象是一个单例*@paramobj*@paramclassFullName*/publicstaticvoidgetMyClass(Objectobj,Stringcl......
  • ESP8266WiFi模块与Android实现数据通信
    ESP8266模块三种模式:    1、STA模式(客户端模式):ESP8266模块通过路由器连接互联网,手机或电脑通过互联网实现对设备的远程控制    2、AP模式(接入点模式):ESP8266模块作为热点,手机或电脑直接与模块连接,实现局域网无线控制    3、STA+AP模式(两种模式并存):ESP826......
  • Unity的IPostGenerateGradleAndroidProject:深入解析与实用案例
    UnityIPostGenerateGradleAndroidProjectUnity是一款流行的跨平台游戏引擎,它支持多种平台,包括Android。在Unity中,我们可以使用IPostGenerateGradleAndroidProject接口来自定义Gradle构建过程。本文将介绍如何使用IPostGenerateGradleAndroidProject接口,并提供三个使用例子。IPos......
  • 给Android开发者Flutter上手指南
    [给Android开发者Flutter上手指南_慕课手记](https://www.imooc.com/article/315337)目录LinearLayout在Flutter中等价于什么(Android)?RelativeLayout在Flutter中等价于什么(Android)?如何使用widget定义布局属性?如何分层布局?如何设置布局样式?ScrollView在Flutter......
  • 【Android基础】【001】Android不同版本介绍
    基本介绍安卓(Android)是谷歌推出的一种基于Linux操作系统的开源智能手机操作系统。下面是各个版本的简要介绍:Android1.0:2008年9月发布,是第一个正式发布的版本。Android1.5:2009年4月发布,命名为“Cupcake”,新增了虚拟键盘、相机等功能。Android1.6:2009年9月发布,命名为“Donut......