[Android][WIFI]手机作AP,关闭移动网络后,STA端断开重连问题分析

这篇具有很好参考价值的文章主要介绍了[Android][WIFI]手机作AP,关闭移动网络后,STA端断开重连问题分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[Android][WIFI]手机作AP,关闭移动网络后,STA端断开重连问题分析

背景描述

测试平台

Android版本:Android P(9.0)

复现步骤

  • 准备两台移动设备,一台作为AP,一台作为STA;
  • 作为AP的设备具备移动网络上网,热点网络分享能力;
  • 打开作为AP的设备的移动网络流量开关,再打开热点;
  • 作为STA的设备接入该AP,并等待其通路判断完成,确保Internet网络访问能力正常;
  • 关闭作为AP的设备的移动网络流量开关;
  • 观察

期望结果

STA端网络保持连接,状态变更为无Internet访问能力提示

实际结果

STA端断开,并随后自动重连成功,状态变更为无Internet访问能力提示

问题分析

WifiStateMachine

打开STA端WiFi Verbose log后,抓取日志,首先确认断开的原因:

01-04 10:01:38.920 24751 24837 D WifiStateMachine:  ConnectedState !CMD_IP_CONFIGURATION_LOST rt=2214117/2214117 0 0 failures: 0/9 7e:d2:c5:43:c8:03 bcn=0
01-04 10:01:38.920 24751 24837 D WifiStateMachine:  L2ConnectedState !CMD_IP_CONFIGURATION_LOST rt=2214117/2214117 0 0 failures: 0/9 7e:d2:c5:43:c8:03 bcn=0
...
01-04 10:01:38.921 25250 25250 D wpa_supplicant: wlan0: Request to deauthenticate - bssid=7e:d2:c5:43:c8:03 pending_bssid=00:00:00:00:00:00 reason=3 (DEAUTH_LEAVING) state=COMPLETED

发现为主动断开,而WifiStateMachine显示状态机在L2ConnectedState处理了CMD_IP_CONFIGURATION_LOST消息;
结合代码来看,WifiStateMachineL2ConnectedState中处理CMD_IP_CONFIGURATION_LOST消息的逻辑中包含handleIpConfigurationLost()方法,后者会调用WifiNative.disconnect()发起断开请求:

//frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
    private void handleIpConfigurationLost() {
        mWifiInfo.setInetAddress(null);
        mWifiInfo.setMeteredHint(false);

        mWifiConfigManager.updateNetworkSelectionStatus(mLastNetworkId,
                WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE);

        /* DHCP times out after about 30 seconds, we do a
         * disconnect thru supplicant, we will let autojoin retry connecting to the network
         */
        mWifiNative.disconnect(mInterfaceName);
    }

    ...
    
	class L2ConnectedState extends State {
		...
        @Override
        public boolean processMessage(Message message) {
			...
            switch (message.what) {
				...
                case CMD_IP_CONFIGURATION_LOST:
                    // Get Link layer stats so that we get fresh tx packet counters.
                    getWifiLinkLayerStats();
                    handleIpConfigurationLost();
                    reportConnectionAttemptEnd(
                            WifiMetrics.ConnectionEvent.FAILURE_DHCP,
                            WifiMetricsProto.ConnectionEvent.HLF_NONE);
                    transitionTo(mDisconnectingState);
                    break;
				...
            }

            return HANDLED;
        }
    }

而发送发送CMD_IP_CONFIGURATION_LOST消息是由构造IpClient时传递的IpClientCallback实例对象回调过来的:

//frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
    private IpClient mIpClient;
    ...
    private FrameworkFacade mFacade;
    ...
	class IpClientCallback extends IpClient.Callback {
		...
        @Override
        public void onProvisioningFailure(LinkProperties newLp) {
            mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST);
            sendMessage(CMD_IP_CONFIGURATION_LOST);
        }
        ...
    }
    ...
	private void setupClientMode() {
		...
        mIpClient = mFacade.makeIpClient(mContext, mInterfaceName, new IpClientCallback());
        mIpClient.setMulticastFilter(true);
        ...
    }

到这里,基本可以确定,是IpClient侧的逻辑,触发了WifiStateMachine.IpClientCallbackonProvisioningFailure()回调方法,导致STA端WLAN断开;

接下来跳转到IpClient继续分析:

IpClient

IpClient侧通常日志较少,需要添加日志:

public class IpClient extends StateMachine {
    private static final boolean DBG = true;
    ...
    private void configureAndStartStateMachine() {
		...
        setInitialState(mStoppedState);
        setDbg("wlan0".equals(mInterfaceName));
		...
    }
    ...
}

复现后可知:

01-04 10:01:38.918 24751 25461 D IpClient.wlan0: handleMessage: E msg.what=6
...
01-04 10:01:38.918 24751 25461 D IpClient.wlan0: processMsg: RunningState
01-04 10:01:38.919 24751 25461 D IpClient.wlan0: Netlink-seen LPs: {InterfaceName: wlan0 LinkAddresses: [fe80::ce88:26ff:fefb:a765/64,192.168.98.129/24,240e:476:bbc2:3fcf:ce88:26ff:fefb:a765/64,240e:476:bbc2:3fcf:40ae:51e9:8141:84b7/64,]  Routes: [fe80::/64 -> :: wlan0,] DnsAddresses: [240e:476:bbc2:3fcf::e6,] UsePrivateDns: false PrivateDnsServerName: null Domains: null MTU: 0}, new LPs: {InterfaceName: wlan0 LinkAddresses: [fe80::ce88:26ff:fefb:a765/64,192.168.98.129/24,240e:476:bbc2:3fcf:ce88:26ff:fefb:a765/64,240e:476:bbc2:3fcf:40ae:51e9:8141:84b7/64,]  Routes: [fe80::/64 -> :: wlan0,192.168.98.0/24 -> 0.0.0.0 wlan0,0.0.0.0/0 -> 192.168.98.27 wlan0,] DnsAddresses: [192.168.98.27,] UsePrivateDns: false PrivateDnsServerName: null Domains: null MTU: 0 TcpBufferSizes: 524288,1048576,2097152,262144,524288,1048576}; old LPs: {InterfaceName: wlan0 LinkAddresses: [fe80::ce88:26ff:fefb:a765/64,192.168.98.129/24,240e:476:bbc2:3fcf:ce88:26ff:fefb:a765/64,240e:476:bbc2:3fcf:40ae:51e9:8141:84b7/64,]  Routes: [fe80::/64 -> :: wlan0,::/0 -> fe80::7cd2:c5ff:fe43:c803 wlan0,240e:476:bbc2:3fcf::/64 -> :: wlan0,192.168.98.0/24 -> 0.0.0.0 wlan0,0.0.0.0/0 -> 192.168.98.27 wlan0,] DnsAddresses: [240e:476:bbc2:3fcf::e6,192.168.98.27,] UsePrivateDns: false PrivateDnsServerName: null Domains: null MTU: 0 TcpBufferSizes: 524288,1048576,2097152,262144,524288,1048576}
01-04 10:01:38.920 24751 25461 D IpClient.wlan0: onProvisioningFailure()

第一句日志输出是在assembleLinkProperties()方法中:

//frameworks/base/services/net/java/android/net/ip/IpClient.java
	private LinkProperties assembleLinkProperties() {
        // [1] Create a new LinkProperties object to populate.
        LinkProperties newLp = new LinkProperties();
        newLp.setInterfaceName(mInterfaceName);

        // [2] Pull in data from netlink:
        //         - IPv4 addresses
        //         - IPv6 addresses
        //         - IPv6 routes
        //         - IPv6 DNS servers
        //
        // N.B.: this is fundamentally race-prone and should be fixed by
        // changing NetlinkTracker from a hybrid edge/level model to an
        // edge-only model, or by giving IpClient its own netlink socket(s)
        // so as to track all required information directly.
        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
            newLp.addRoute(route);
        }
        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());

        // [3] Add in data from DHCPv4, if available.
        //
        // mDhcpResults is never shared with any other owner so we don't have
        // to worry about concurrent modification.
        if (mDhcpResults != null) {
            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
                newLp.addRoute(route);
            }
            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
            newLp.setDomains(mDhcpResults.domains);

            if (mDhcpResults.mtu != 0) {
                newLp.setMtu(mDhcpResults.mtu);
            }
        }

        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
            newLp.setTcpBufferSizes(mTcpBufferSizes);
        }
        if (mHttpProxy != null) {
            newLp.setHttpProxy(mHttpProxy);
        }

        // [5] Add data from InitialConfiguration
        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
            InitialConfiguration config = mConfiguration.mInitialConfig;
            // Add InitialConfiguration routes and dns server addresses once all addresses
            // specified in the InitialConfiguration have been observed with Netlink.
            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
                for (IpPrefix prefix : config.directlyConnectedRoutes) {
                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName));
                }
            }
            addAllReachableDnsServers(newLp, config.dnsServers);
        }
        final LinkProperties oldLp = mLinkProperties;
        if (DBG) {
            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
                    netlinkLinkProperties, newLp, oldLp));
        }

        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
        return newLp;
    }

结合状态机的日志,可知是RunningState处理EVENT_NETLINK_LINKPROPERTIES_CHANGED消息时调用的assembleLinkProperties()方法:

//frameworks/base/services/net/java/android/net/ip/IpClient.java
	...
	class RunningState extends State {
        private ConnectivityPacketTracker mPacketTracker;
        private boolean mDhcpActionInFlight;
        ...
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
				...
                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
                        transitionTo(mStoppingState);
                    }
                    break;
				...
            }
			...
        }
    }

结合代码分析,可知这部分逻辑应该是这样的:

  1. AP端关闭移动网络流量开关后,STA端IPV6地址与路由表发生改变;
  2. NetlinkTrackerNetd接收到这些改变的事件,并通过NetlinkTracker.Callback.update()回调给到IpClient.mNetlinkTracker
  3. IpClient.mNetlinkTracker收到update()事件回调后,向IpClient状态机发送EVENT_NETLINK_LINKPROPERTIES_CHANGED消息;
  4. IpClient如果此时处于RunningState,那么在处理EVENT_NETLINK_LINKPROPERTIES_CHANGED消息时,会触发onProvisioningFailure()方法回调;
  5. onProvisioningFailure()方法回调会通过构造时注册进来的IpClient.Callback回调实例,通知到WifiStateMachine,后者会执行断开逻辑;

梳理完了整个流程,接下来就需要分析上面的第4步中最后一个疑点——onProvisioningFailure()为何会执行;

前面已经分析到了: IpClientRunningState下处理EVENT_NETLINK_LINKPROPERTIES_CHANGED消息会调用handleLinkPropertiesUpdate()方法,参数为SEND_CALLBACKS,恒为true

//frameworks/base/services/net/java/android/net/ip/IpClient.java
    private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
        switch (delta) {
			...
            case LOST_PROVISIONING:
                if (DBG) { Log.d(mTag, "onProvisioningFailure()"); }
                recordMetric(IpManagerEvent.PROVISIONING_FAIL);
                mCallback.onProvisioningFailure(newLp);
                break;
			...
        }
    }

    ...

    // Returns false if we have lost provisioning, true otherwise.
	private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
        final LinkProperties newLp = assembleLinkProperties();
        if (Objects.equals(newLp, mLinkProperties)) {
            return true;
        }
        final ProvisioningChange delta = setLinkProperties(newLp);
        if (sendCallbacks) {
            dispatchCallback(delta, newLp);
        }
        return (delta != ProvisioningChange.LOST_PROVISIONING);
    }

handleLinkPropertiesUpdate()方法实现内部,有一个名为delta的局部常量,类型为ProvisioningChange枚举,当delta这个局部常量赋值为setLinkProperties()方法的返回结果;

如果返回结果为LOST_PROVISIONING,则会通过dispatchCallback()方法触发onProvisioningFailure()回调,从而出现上面整个链路,导致STA断连;

handleLinkPropertiesUpdate()方法内部,最重要的两个方法是:assembleLinkProperties()setLinkProperties(newLp)

依次来看:

//frameworks/base/services/net/java/android/net/ip/IpClient.java

	private LinkProperties assembleLinkProperties() {
        // [1] Create a new LinkProperties object to populate.
        LinkProperties newLp = new LinkProperties();
        newLp.setInterfaceName(mInterfaceName);

        // [2] Pull in data from netlink:
        //         - IPv4 addresses
        //         - IPv6 addresses
        //         - IPv6 routes
        //         - IPv6 DNS servers
        //
        // N.B.: this is fundamentally race-prone and should be fixed by
        // changing NetlinkTracker from a hybrid edge/level model to an
        // edge-only model, or by giving IpClient its own netlink socket(s)
        // so as to track all required information directly.
        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
            newLp.addRoute(route);
        }
        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());

        // [3] Add in data from DHCPv4, if available.
        //
        // mDhcpResults is never shared with any other owner so we don't have
        // to worry about concurrent modification.
        if (mDhcpResults != null) {
            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
                newLp.addRoute(route);
            }
            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
            newLp.setDomains(mDhcpResults.domains);

            if (mDhcpResults.mtu != 0) {
                newLp.setMtu(mDhcpResults.mtu);
            }
        }

        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
            newLp.setTcpBufferSizes(mTcpBufferSizes);
        }
        if (mHttpProxy != null) {
            newLp.setHttpProxy(mHttpProxy);
        }

        // [5] Add data from InitialConfiguration
        if (mConfiguration != null && mConfiguration.mInitialConfig != null) {
            InitialConfiguration config = mConfiguration.mInitialConfig;
            // Add InitialConfiguration routes and dns server addresses once all addresses
            // specified in the InitialConfiguration have been observed with Netlink.
            if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) {
                for (IpPrefix prefix : config.directlyConnectedRoutes) {
                    newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName));
                }
            }
            addAllReachableDnsServers(newLp, config.dnsServers);
        }
        final LinkProperties oldLp = mLinkProperties;
        if (DBG) {
            Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
                    netlinkLinkProperties, newLp, oldLp));
        }

        // TODO: also learn via netlink routes specified by an InitialConfiguration and specified
        // from a static IP v4 config instead of manually patching them in in steps [3] and [5].
        return newLp;
    }

assembleLinkProperties()这个方法主要完成了如下任务:

  1. 通过 mNetlinkTracker.getLinkProperties()获取当前探测到的最新的链路信息,并封装为LinkProperties返回,赋值给netlinkLinkProperties
  2. netlinkLinkProperties中的需要关注的信息(LinkAddressesRouteInfo等)拷贝到newLp这个局部变量中;
  3. 返回newLp

handleLinkPropertiesUpdate()方法内在收到assembleLinkProperties()方法的返回值后,会判断与当前的成员变量mLinkProperties是否相同;

LinkProperties重写了equals方法:

//frameworks/base/core/java/android/net/LinkProperties.java
	...
    @Override
    /**
     * Compares this {@code LinkProperties} instance against the target
     * LinkProperties in {@code obj}. Two LinkPropertieses are equal if
     * all their fields are equal in values.
     *
     * For collection fields, such as mDnses, containsAll() is used to check
     * if two collections contains the same elements, independent of order.
     * There are two thoughts regarding containsAll()
     * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal.
     * 2. Worst case performance is O(n^2).
     *
     * @param obj the object to be tested for equality.
     * @return {@code true} if both objects are equal, {@code false} otherwise.
     */
    public boolean equals(Object obj) {
        if (this == obj) return true;

        if (!(obj instanceof LinkProperties)) return false;

        LinkProperties target = (LinkProperties) obj;
        /**
         * This method does not check that stacked interfaces are equal, because
         * stacked interfaces are not so much a property of the link as a
         * description of connections between links.
         */
        return isIdenticalInterfaceName(target)
                && isIdenticalAddresses(target)
                && isIdenticalDnses(target)
                && isIdenticalPrivateDns(target)
                && isIdenticalValidatedPrivateDnses(target)
                && isIdenticalRoutes(target)
                && isIdenticalHttpProxy(target)
                && isIdenticalStackedLinks(target)
                && isIdenticalMtu(target)
                && isIdenticalTcpBufferSizes(target);
    }
    ...

由此可见,满足equals的要求非常苛刻,只要有任何变动,都会导致返回值为false

回到此问题,由于IPV6的相关地址变更,其关联的路由规则与地址信息均会发生改变,因此这里必然会返回false

由此,我们来看第二个重要的方法——setLinkProperties()

//frameworks/base/services/net/java/android/net/ip/IpClient.java
	...
    static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) {
        // For historical reasons, we should connect even if all we have is
        // an IPv4 address and nothing else.
        if (lp.hasIPv4Address() || lp.isProvisioned()) {
            return true;
        }
        if (config == null) {
            return false;
        }

        // When an InitialConfiguration is specified, ignore any difference with previous
        // properties and instead check if properties observed match the desired properties.
        return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes());
    }

	...

    private ProvisioningChange compareProvisioning(LinkProperties oldLp, LinkProperties newLp) {
        ProvisioningChange delta;
        InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null;
        final boolean wasProvisioned = isProvisioned(oldLp, config);
        final boolean isProvisioned = isProvisioned(newLp, config);

        if (!wasProvisioned && isProvisioned) {
            delta = ProvisioningChange.GAINED_PROVISIONING;
        } else if (wasProvisioned && isProvisioned) {
            delta = ProvisioningChange.STILL_PROVISIONED;
        } else if (!wasProvisioned && !isProvisioned) {
            delta = ProvisioningChange.STILL_NOT_PROVISIONED;
        } else {
			...
            delta = ProvisioningChange.LOST_PROVISIONING;
        }

        final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
        final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
        final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
		...
        final boolean ignoreIPv6ProvisioningLoss = (mMultinetworkPolicyTracker != null)
                && !mMultinetworkPolicyTracker.getAvoidBadWifi();

		...
        if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
            delta = ProvisioningChange.LOST_PROVISIONING;
        }
		...
        if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
            delta = ProvisioningChange.LOST_PROVISIONING;
        }

        return delta;
    }

    // Updates all IpClient-related state concerned with LinkProperties.
    // Returns a ProvisioningChange for possibly notifying other interested
    // parties that are not fronted by IpClient.
    private ProvisioningChange setLinkProperties(LinkProperties newLp) {
		...
        ProvisioningChange delta = compareProvisioning(mLinkProperties, newLp);
        mLinkProperties = new LinkProperties(newLp);
		...
        return delta;
    }

	...

    // Returns false if we have lost provisioning, true otherwise.
    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
		...
        final ProvisioningChange delta = setLinkProperties(newLp);
        if (sendCallbacks) {
            dispatchCallback(delta, newLp);
        }
        return (delta != ProvisioningChange.LOST_PROVISIONING);
    }

这里方法跳转比较多,概括一下:

  1. setLinkProperties由于需要一个ProvisioningChange枚举的返回结果,因此不仅仅是将参数生拷贝到成员变量mLinkProperties,在此之前需要调用compareProvisioning方法对mLinkProperties与传入参数newLp进行对比,并将差异返回,赋值给局部常量delta,后者也是整个setLinkProperties方法的返回结果;
  2. compareProvisioning方法主要通过对比两个传入参数的isProvisioned方法返回结果,来判定这次变动是GAINED_PROVISIONINGSTILL_PROVISIONEDSTILL_NOT_PROVISIONED,还是LOST_PROVISIONING
  3. 此外,如果compareProvisioning方法内的局部变量ignoreIPv6ProvisioningLoss不为true,IPV6地址、网关、DNS的丢失也会导致返回结果为LOST_PROVISIONING

而此问题出现,就是满足了第3条条件所致;

解决方案

由上可知,此行为是AOSP原生逻辑,旨在使STA自动规避无法上网的AP;

因此:文章来源地址https://www.toymoban.com/news/detail-495316.html

  1. 此问题若非强需求,可以不处理;
  2. 若需要屏蔽掉此行为,只需将config_networkAvoidBadWifi修改为0即可;

到了这里,关于[Android][WIFI]手机作AP,关闭移动网络后,STA端断开重连问题分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 12 Wifi 开发(获取列表、连接、断开连接)

    获取Wifi列表: 扫描(这个方法早在Android 9.0 就被弃用), 不过如果不调用的话是没法及时获取Wifi列表的广播的。 (不需要也能正常获取,没有延迟,经实验毫无区别) 创建广播并接收: 配置并连接( 无系统签名 ): 配置并连接( 有系统签名 ): 断开连接(无系统签名

    2024年02月03日
    浏览(29)
  • Google系列Android手机无法联网/无法上网/WIFI网络受限等问题的解决方法

    https://m.weishi100.com/mweb/single/1666650236443/?id=8960958 https://m.weishi100.com/mweb/series/?id=1372437 https://m.weishi100.com/mweb/series/?id=1373351

    2024年02月04日
    浏览(44)
  • RabbitMQ连接断开自动重连问题解决

    RabbitMQ是一个功能强大的消息代理,被广泛用于构建分布式应用程序。然而,有时候在使用RabbitMQ时会遇到连接断开的问题,这可能会导致消息传递中断和应用程序的不可用性。在本文中,我们将探讨如何解决RabbitMQ连接断开的问题,并提供相应的源代码示例。 当使用RabbitMQ时

    2024年02月05日
    浏览(43)
  • RK3288 Android5.1添加WiFi&BT模块AP6212

    CPU:RK3288 系统:Android 5.1 注:RK3288系统,目前 Android 5.0 Kernel 3.10 SDK 支持 Braodcom,Realtek 等 WiFi BT 模块 各个 WiFi BT 模块已经做到动态兼容,Android 上层不再需要像以前一样进 行特定宏的配置 此文是手动添加AP6212A的例程。 1、在设备树中修改 wifi 芯片为 ap6212a(找到自己对应的

    2024年02月07日
    浏览(27)
  • nginx代理socket链接集群后,频繁断开重连

    nginx使用集群模式代理多个socket链接,socket链接频繁断开重连 1、nginx错误日志 2、nginx访问日志 从日志上可以看到,断开重连频率非常高,每隔几十毫秒就会链接一次 是nginx集群的负载均衡策略有问题,因为没有在 test_socket集群 指定策略,所以nginx默认使用的是 轮询策略 那为

    2024年02月09日
    浏览(34)
  • 实际案例记录:华三AP,wa6638i,能获取管理地址,手机连接不上wifi,一直显示获取ip中

    基本配置:wa6638i,硬件端口:1、电口10G+POE,2、电口10G+POE,3、光口SFP-10G,4、串口,5、POE OUT输出物联模块端口   使用问题:AP在AC控制器上线,并获取到管理vlan地址。电脑连接上wifi,可是网络适配器显示没有获取到业务vlan地址。手机连接wifi显示IP地址获取中一直连接不上

    2024年02月10日
    浏览(58)
  • 手机移动数据关闭了 会影响什么

    今天将android手机关闭了移动数据,又怕影响别的wifi上网之类的,其实关闭了就不会才产生流量使用和费用,wifi可以正常使用。 你关闭了,天气等软件就不能再更新了手机移动数据,这样既省电还省钱了,不过如果用微信,qq的时候需要开启的,所以我们一般晚上睡觉的时候关

    2024年02月05日
    浏览(35)
  • ESP8266WiFi模块与Android APP实现数据传输(二)---AP模式通讯

    前言: 1.ESP8266模块设定: (1)准备阶段: (2)AT指令配置WiFi模块: 2.Android手机端APP设置: 3.ESP8266与APP通讯:  4.串口调试器和APP程序等资源下载途径         本文主要介绍一下ESP8266WiFi模块与Andriod APP实现数据传输的 AP模式 通讯。 ESP8266模块 三种模式 :         1、STA模式

    2024年02月01日
    浏览(41)
  • 利用Api接口实现手机网络连接断开的监听

    在今天的移动互联网时代,手机已经成为了人们不可或缺的重要工具,而手机的联网状态也是我们经常需要关注的一个问题。我们需要保证手机网络处于正常的连接状态,但是有时候,由于种种原因,手机的网络可能会断开,这时我们需要及时发现,并进行相应的处理措施。

    2024年02月09日
    浏览(36)
  • 一加8手机【ColorOS Android 13】使用Android Studio在Debug断点调试时自动断开崩溃

    一加8手机(系统是ColorOS  Android版本: 13) 在使用android studio进行usb调试过程中, 总是在几秒钟之后就自动崩溃退出应用(代码正常,使用其他测试机正常调试), 调试自然也就断开了;  解决办法: 将【禁止权限监控】开关 打开即可; --【其他设置】--【开发者选项】--【应用】--【禁止

    2024年02月12日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包