Android DNS Resolver

2023-05-16

DNS 解析器(DNS Resolver)

DNS 解析器模块可保护用户免受 DNS 拦截和配置更新攻击,并改进了 DNS 解析的网络性能。此模块包含用于实现 DNS 桩解析器的代码,该解析器可将 www.google.com 等名称转换为 IP 地址(例如 2001:db8::1)。DNS 桩解析器支持 Java API 元素(如 InetAddress#getAllByName 和 Network#getAllByName)以及原生网络功能,且可发送和接收 DNS 查询以及缓存结果。

Android 10 中的变化

在搭载 Android 9 及更低版本的设备上,DNS 解析器代码分布在 Bionic 和 netd 上。DNS 查找操作集中在 netd 守护程序中,以便进行系统级缓存,而应用在 Bionic 中调用函数(例如 getaddrinfo)。查询会通过 UNIX 套接字发送到 /dev/socket/dnsproxyd,再到 netd 守护程序,该守护程序会解析请求并再次调用 getaddrinfo,以发出 DNS 查找请求,然后它会缓存结果以供其他应用使用。DNS 解析器实现主要包含在 bionic/libc/dns/ 中,部分包含在 system/netd/server/dns 中。

Android 10 将 DNS 解析器代码移至 system/netd/resolv,,将其转换为 C++,然后对代码进行了翻新和重构。由于应用兼容性方面的原因,Bionic 中的代码继续存在,但系统不会再调用它们。以下源文件路径受到重构的影响:

  • bionic/libc/dns
  • system/netd/client
  • system/netd/server/dns
  • system/netd/server/DnsProxyListener.*
  • system/netd/resolv

(1)获取ip地址(域名–>IP地址)

ConnectivityService.updateDnses() ->

DnsManager.setDnsConfigurationForNetwork() ->

mDnsResolver.setResolverConfiguration() -> IDnsResolver.aidl ()

DnsResolverService.setResolverConfiguration()  ->

ResolverController.setResolverConfiguration() ->

res_cache.int resolv_set_nameservers_for_net() ->

getaddrinfo.getaddrinfo_numeric() -> getaddrinfo.android_getaddrinfofornetcontext(hostname, servname, &hints, &netcontext, result);

 

(2)DNS server list 设置(set name servers for a network)

_resolv_set_nameservers_for_net

 


http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/InetAddress.java#1105

1077    /**
1078     * Determines the IP address of a host, given the host's name.
1097     * @param      host   the specified host, or {@code null}.
1098     * @return     an IP address for the given host name.
1104     */
1105    public static InetAddress getByName(String host)
1106        throws UnknownHostException {
1107        // Android-changed: Rewritten on the top of Libcore.os.
1108        return impl.lookupAllHostAddr(host, NETID_UNSET)[0];
1109    }

1111    /**
1112     * Given the name of a host, returns an array of its IP addresses,
1113     * based on the configured name service on the system.
1139     * @param      host   the name of the host, or {@code null}.
1140     * @return     an array of all the IP addresses for a given host name.
1149     */
1150    public static InetAddress[] getAllByName(String host)
1151        throws UnknownHostException {
1152        // Android-changed: Resolves a hostname using Libcore.os.
1153        // Also, returns both the Inet4 and Inet6 loopback for null/empty host
1154        return impl.lookupAllHostAddr(host, NETID_UNSET).clone();
1155    }


lookupAllHostAddr在Android M上的名字叫做getAllByNameImpl

http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java#88

79    // BEGIN Android-changed: Rewrote hostname lookup methods on top of Libcore.os.
80    /*
81    public native String getLocalHostName() throws UnknownHostException;
82    public native InetAddress[]
83        lookupAllHostAddr(String hostname) throws UnknownHostException;
84    public native String getHostByAddr(byte[] addr) throws UnknownHostException;
85    private native boolean isReachable0(byte[] addr, int scope, int timeout, byte[] inf, int ttl, int if_scope) throws IOException;
86    */
87    @Override
88    public InetAddress[] lookupAllHostAddr(String host, int netId) throws UnknownHostException {
89        if (host == null || host.isEmpty()) {
90            // Android-changed: Return both the Inet4 and Inet6 loopback addresses
91            // when host == null or empty.
92            return loopbackAddresses();
93        }
94
95        // Is it a numeric address?
96        InetAddress result = InetAddress.parseNumericAddressNoThrow(host);
97        if (result != null) {
98            result = InetAddress.disallowDeprecatedFormats(host, result);
99            if (result == null) {
100                throw new UnknownHostException("Deprecated IPv4 address format: " + host);
101            }
102            return new InetAddress[] { result };
103        }
104
105        return lookupHostByName(host, netId);
106    }

323    // BEGIN Android-changed: Let loopbackAddresses() return both Inet4 and Inet6 loopbacks.
324    @Override
325    public InetAddress[] loopbackAddresses() {
326        synchronized (Inet6AddressImpl.class) {
327            // We avoid initializing anyLocalAddress during <clinit> to avoid issues
328            // caused by the dependency chains of these classes. InetAddress depends on
329            // InetAddressImpl, but Inet6Address & Inet4Address are its subclasses.
330            // Also see {@code anyLocalAddress).
331            if (loopbackAddresses == null) {
332                loopbackAddresses = new InetAddress[]{Inet6Address.LOOPBACK, Inet4Address.LOOPBACK};
333            }
334
335            return loopbackAddresses;
336        }
337    }


http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/InetAddress.java#1622

1622    static InetAddress parseNumericAddressNoThrow(String address) {
1623        // Accept IPv6 addresses (only) in square brackets for compatibility.
1624        if (address.startsWith("[") && address.endsWith("]") && address.indexOf(':') != -1) {
1625            address = address.substring(1, address.length() - 1);
1626        }
1627        StructAddrinfo hints = new StructAddrinfo();
1628        hints.ai_flags = AI_NUMERICHOST;
1629        InetAddress[] addresses = null;
1630        try {
1631            addresses = Libcore.os.android_getaddrinfo(address, hints, NETID_UNSET);
1632        } catch (GaiException ignored) {
1633        }
1634        return (addresses != null) ? addresses[0] : null;
1635    }

http://androidxref.com/9.0.0_r3/xref/libcore/ojluni/src/main/java/java/net/Inet6AddressImpl.java#115

108    /**
109     * Resolves a hostname to its IP addresses using a cache.
110     *
111     * @param host the hostname to resolve.
112     * @param netId the network to perform resolution upon.
113     * @return the IP addresses of the host.
114     */
115    private static InetAddress[] lookupHostByName(String host, int netId)
116            throws UnknownHostException {
117        BlockGuard.getThreadPolicy().onNetwork();
118        // Do we have a result cached?
119        Object cachedResult = addressCache.get(host, netId);
120        if (cachedResult != null) {
121            if (cachedResult instanceof InetAddress[]) {
122                // A cached positive result.
123                return (InetAddress[]) cachedResult;
124            } else {
125                // A cached negative result.
126                throw new UnknownHostException((String) cachedResult);
127            }
128        }
129        try {
130            StructAddrinfo hints = new StructAddrinfo();
131            hints.ai_flags = AI_ADDRCONFIG;
132            hints.ai_family = AF_UNSPEC;
133            // If we don't specify a socket type, every address will appear twice, once
134            // for SOCK_STREAM and one for SOCK_DGRAM. Since we do not return the family
135            // anyway, just pick one.
136            hints.ai_socktype = SOCK_STREAM;
137            InetAddress[] addresses = Libcore.os.android_getaddrinfo(host, hints, netId);
138            // TODO: should getaddrinfo set the hostname of the InetAddresses it returns?
139            for (InetAddress address : addresses) {
140                address.holder().hostName = host;
141                address.holder().originalHostName = host;
142            }
143            addressCache.put(host, netId, addresses);
144            return addresses;
145        } catch (GaiException gaiException) {
146            // If the failure appears to have been a lack of INTERNET permission, throw a clear
147            // SecurityException to aid in debugging this common mistake.
148            // http://code.google.com/p/android/issues/detail?id=15722
149            if (gaiException.getCause() instanceof ErrnoException) {
150                if (((ErrnoException) gaiException.getCause()).errno == EACCES) {
151                    throw new SecurityException("Permission denied (missing INTERNET permission?)", gaiException);
152                }
153            }
154            // Otherwise, throw an UnknownHostException.
155            String detailMessage = "Unable to resolve host \"" + host + "\": " + Libcore.os.gai_strerror(gaiException.error);
156            addressCache.putUnknownHost(host, netId, detailMessage);
157            throw gaiException.rethrowAsUnknownHostException(detailMessage);
158        }
159    }

上面都调用了Libcore.os.android_getaddrinfo

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/Libcore.java#19

19public final class Libcore {
20    private Libcore() { }
21
22    /**
23     * Direct access to syscalls. Code should strongly prefer using {@link #os}
24     * unless it has a strong reason to bypass the helpful checks/guards that it
25     * provides.
26     */
27    public static Os rawOs = new Linux();
28
29    /**
30     * Access to syscalls with helpful checks/guards.
31     */
32    public static Os os = new BlockGuardOs(rawOs);
33}

Os对象是一系列系统调用的抽象接口,从LibCore.java中可以看出它是通过Linux这个类实现的

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/Linux.java#53

48public final class Linux implements Os {
49    Linux() { }

53    public native InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/BlockGuardOs.java#164

40/**
41 * Informs BlockGuard of any activity it should be aware of.
42 */
43public class BlockGuardOs extends ForwardingOs {
44    public BlockGuardOs(Os os) {
45        super(os);
46    }


164    @Override public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException {
165        // With AI_NUMERICHOST flag set, the node must a numerical network address, therefore no
166        // host address lookups will be performed. In this case, it is fine to perform on main
167        // thread.
168        boolean isNumericHost = (hints.ai_flags & AI_NUMERICHOST) != 0;
169        if (!isNumericHost) {
170            BlockGuard.getThreadPolicy().onNetwork();
171        }
172        return os.android_getaddrinfo(node, hints, netId);
173    }

再找OS类

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/java/libcore/io/Os.java#50

47public interface Os {
50    public InetAddress[] android_getaddrinfo(String node, StructAddrinfo hints, int netId) throws GaiException;

参考

  • android 从java到C层文件读取流程
  • 深入理解Android的file.exists()

得知Linux.java通过JNI (libcore_io_Linux.cpp)调用linux的posix API,那么知道了,C层的实现都在libcore_io_Linux.cpp中,咱们来看下。

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/native/libcore_io_Linux.cpp#1244

1244static jobjectArray Linux_android_getaddrinfo(JNIEnv* env, jobject, jstring javaNode,
1245        jobject javaHints, jint netId) {
1246    ScopedUtfChars node(env, javaNode);
1247    if (node.c_str() == NULL) {
1248        return NULL;
1249    }
1250
1251    static jfieldID flagsFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_flags", "I");
1252    static jfieldID familyFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_family", "I");
1253    static jfieldID socktypeFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_socktype", "I");
1254    static jfieldID protocolFid = env->GetFieldID(JniConstants::structAddrinfoClass, "ai_protocol", "I");
1255
1256    addrinfo hints;
1257    memset(&hints, 0, sizeof(hints));
1258    hints.ai_flags = env->GetIntField(javaHints, flagsFid);
1259    hints.ai_family = env->GetIntField(javaHints, familyFid);
1260    hints.ai_socktype = env->GetIntField(javaHints, socktypeFid);
1261    hints.ai_protocol = env->GetIntField(javaHints, protocolFid);
1262
1263    addrinfo* addressList = NULL;
1264    errno = 0;
1265    int rc = android_getaddrinfofornet(node.c_str(), NULL, &hints, netId, 0, &addressList);
1266    std::unique_ptr<addrinfo, addrinfo_deleter> addressListDeleter(addressList);
1267    if (rc != 0) {
1268        throwGaiException(env, "android_getaddrinfo", rc);
1269        return NULL;
1270    }
1271
1272    // Count results so we know how to size the output array.
1273    int addressCount = 0;
1274    for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
1275        if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
1276            ++addressCount;
1277        } else {
1278            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
1279        }
1280    }
1281    if (addressCount == 0) {
1282        return NULL;
1283    }
1284
1285    // Prepare output array.
1286    jobjectArray result = env->NewObjectArray(addressCount, JniConstants::inetAddressClass, NULL);
1287    if (result == NULL) {
1288        return NULL;
1289    }
1290
1291    // Examine returned addresses one by one, save them in the output array.
1292    int index = 0;
1293    for (addrinfo* ai = addressList; ai != NULL; ai = ai->ai_next) {
1294        if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) {
1295            // Unknown address family. Skip this address.
1296            ALOGE("android_getaddrinfo unexpected ai_family %i", ai->ai_family);
1297            continue;
1298        }
1299
1300        // Convert each IP address into a Java byte array.
1301        sockaddr_storage& address = *reinterpret_cast<sockaddr_storage*>(ai->ai_addr);
1302        ScopedLocalRef<jobject> inetAddress(env, sockaddrToInetAddress(env, address, NULL));
1303        if (inetAddress.get() == NULL) {
1304            return NULL;
1305        }
1306        env->SetObjectArrayElement(result, index, inetAddress.get());
1307        ++index;
1308    }
1309    return result;
1310}

调用android_getaddrinfofornet()

http://androidxref.com/9.0.0_r3/xref/libcore/luni/src/main/native/Portability.h#28

28static inline int android_getaddrinfofornet(const char* hostname, const char* servname,
29    const struct addrinfo* hints, unsigned /*netid*/, unsigned /*mark*/, struct addrinfo** res) {
30  return getaddrinfo(hostname, servname, hints, res);
31}

最终调用到bionic/libc/dns/net/getaddrinfo.c

http://androidxref.com/9.0.0_r3/xref/bionic/libc/dns/net/getaddrinfo.c#564

562__BIONIC_WEAK_FOR_NATIVE_BRIDGE
563int
564getaddrinfo(const char *hostname, const char *servname,
565    const struct addrinfo *hints, struct addrinfo **res)
566{
567	return android_getaddrinfofornet(hostname, servname, hints, NETID_UNSET, MARK_UNSET, res);
568}

570__BIONIC_WEAK_FOR_NATIVE_BRIDGE
571int
572android_getaddrinfofornet(const char *hostname, const char *servname,
573    const struct addrinfo *hints, unsigned netid, unsigned mark, struct addrinfo **res)
574{
575	struct android_net_context netcontext = {
576		.app_netid = netid,
577		.app_mark = mark,
578		.dns_netid = netid,
579		.dns_mark = mark,
580		.uid = NET_CONTEXT_INVALID_UID,
581        };
582	return android_getaddrinfofornetcontext(hostname, servname, hints, &netcontext, res);
583}
584
585__BIONIC_WEAK_FOR_NATIVE_BRIDGE
586int
587android_getaddrinfofornetcontext(const char *hostname, const char *servname,
588    const struct addrinfo *hints, const struct android_net_context *netcontext,
589    struct addrinfo **res)
590{
591	struct addrinfo sentinel;
592	struct addrinfo *cur;
593	int error = 0;
594	struct addrinfo ai;
595	struct addrinfo ai0;
596	struct addrinfo *pai;
597	const struct explore *ex;
598
599	/* hostname is allowed to be NULL */
600	/* servname is allowed to be NULL */
601	/* hints is allowed to be NULL */
602	assert(res != NULL);
603	assert(netcontext != NULL);
604	memset(&sentinel, 0, sizeof(sentinel));
605	cur = &sentinel;
606	pai = &ai;
607	pai->ai_flags = 0;
608	pai->ai_family = PF_UNSPEC;
609	pai->ai_socktype = ANY;
610	pai->ai_protocol = ANY;
611	pai->ai_addrlen = 0;
612	pai->ai_canonname = NULL;
613	pai->ai_addr = NULL;
614	pai->ai_next = NULL;
615
616	if (hostname == NULL && servname == NULL)
617		return EAI_NONAME;
618	if (hints) {
619		/* error check for hints */
620		if (hints->ai_addrlen || hints->ai_canonname ||
621		    hints->ai_addr || hints->ai_next)
622			ERR(EAI_BADHINTS); /* xxx */
623		if (hints->ai_flags & ~AI_MASK)
624			ERR(EAI_BADFLAGS);
625		switch (hints->ai_family) {
626		case PF_UNSPEC:
627		case PF_INET:
628#ifdef INET6
629		case PF_INET6:
630#endif
631			break;
632		default:
633			ERR(EAI_FAMILY);
634		}
635		memcpy(pai, hints, sizeof(*pai));
636
637		/*
638		 * if both socktype/protocol are specified, check if they
639		 * are meaningful combination.
640		 */
641		if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
642			for (ex = explore; ex->e_af >= 0; ex++) {
643				if (pai->ai_family != ex->e_af)
644					continue;
645				if (ex->e_socktype == ANY)
646					continue;
647				if (ex->e_protocol == ANY)
648					continue;
649				if (pai->ai_socktype == ex->e_socktype
650				 && pai->ai_protocol != ex->e_protocol) {
651					ERR(EAI_BADHINTS);
652				}
653			}
654		}
655	}
656
657	/*
658	 * check for special cases.  (1) numeric servname is disallowed if
659	 * socktype/protocol are left unspecified. (2) servname is disallowed
660	 * for raw and other inet{,6} sockets.
661	 */
662	if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
663#ifdef PF_INET6
664	 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
665#endif
666	    ) {
667		ai0 = *pai;	/* backup *pai */
668
669		if (pai->ai_family == PF_UNSPEC) {
670#ifdef PF_INET6
671			pai->ai_family = PF_INET6;
672#else
673			pai->ai_family = PF_INET;
674#endif
675		}
676		error = get_portmatch(pai, servname);
677		if (error)
678			ERR(error);
679
680		*pai = ai0;
681	}
682
683	ai0 = *pai;
684
685	/* NULL hostname, or numeric hostname */
686	for (ex = explore; ex->e_af >= 0; ex++) {
687		*pai = ai0;
688
689		/* PF_UNSPEC entries are prepared for DNS queries only */
690		if (ex->e_af == PF_UNSPEC)
691			continue;
692
693		if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
694			continue;
695		if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
696			continue;
697		if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
698			continue;
699
700		if (pai->ai_family == PF_UNSPEC)
701			pai->ai_family = ex->e_af;
702		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
703			pai->ai_socktype = ex->e_socktype;
704		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
705			pai->ai_protocol = ex->e_protocol;
706
707		if (hostname == NULL)
708			error = explore_null(pai, servname, &cur->ai_next);
709		else
710			error = explore_numeric_scope(pai, hostname, servname,
711			    &cur->ai_next);
712
713		if (error)
714			goto free;
715
716		while (cur->ai_next)
717			cur = cur->ai_next;
718	}
719
720	/*
721	 * XXX
722	 * If numeric representation of AF1 can be interpreted as FQDN
723	 * representation of AF2, we need to think again about the code below.
724	 */
725	if (sentinel.ai_next)
726		goto good;
727
728	if (hostname == NULL)
729		ERR(EAI_NODATA);
730	if (pai->ai_flags & AI_NUMERICHOST)
731		ERR(EAI_NONAME);
732
733#if defined(__ANDROID__)
734	int gai_error = android_getaddrinfo_proxy(
735		hostname, servname, hints, res, netcontext->app_netid);
736	if (gai_error != EAI_SYSTEM) {
737		return gai_error;
738	}
739#endif
740
741	/*
742	 * hostname as alphabetical name.
743	 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
744	 * outer loop by AFs.
745	 */
746	for (ex = explore; ex->e_af >= 0; ex++) {
747		*pai = ai0;
748
749		/* require exact match for family field */
750		if (pai->ai_family != ex->e_af)
751			continue;
752
753		if (!MATCH(pai->ai_socktype, ex->e_socktype,
754				WILD_SOCKTYPE(ex))) {
755			continue;
756		}
757		if (!MATCH(pai->ai_protocol, ex->e_protocol,
758				WILD_PROTOCOL(ex))) {
759			continue;
760		}
761
762		if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
763			pai->ai_socktype = ex->e_socktype;
764		if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
765			pai->ai_protocol = ex->e_protocol;
766
767		error = explore_fqdn(
768			pai, hostname, servname, &cur->ai_next, netcontext);
769
770		while (cur && cur->ai_next)
771			cur = cur->ai_next;
772	}
773
774	/* XXX */
775	if (sentinel.ai_next)
776		error = 0;
777
778	if (error)
779		goto free;
780	if (error == 0) {
781		if (sentinel.ai_next) {
782 good:
783			*res = sentinel.ai_next;
784			return SUCCESS;
785		} else
786			error = EAI_FAIL;
787	}
788 free:
789 bad:
790	if (sentinel.ai_next)
791		freeaddrinfo(sentinel.ai_next);
792	*res = NULL;
793	return error;
794}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android DNS Resolver 的相关文章

随机推荐

  • VC中自定义打印调试信息函数,打印调试信息到DebugView上

    该文档参考了以下网友的文章 xff0c 在此表示感谢 1 xff08 更新 xff09 OutputDebugString函数简单封装 xff0c 实现格式化打印输出 xff08 VC 43 43 xff09 链接 xff1a http b
  • C语言编译器之三,VC++

    三 Visual C编译器 Microsoft Visual C 43 43 xff08 简称Visual C 43 43 MSVC VS或VC xff09 是微软公司的免费C 43 43 编译器与开发工具 xff0c 具有集成开发环境 x
  • 彻底弄懂计算机中的大端小端

    大端与小端这个问题在做和其他设备交换原始字节数据的时候是非常重要的概念 xff0c 也是必须要掌握的内容 xff0c 但是很多人就是仅仅是稍微有些了解 xff0c 但每次真正去做东西的时候 xff0c 还是要花半天去想 xff0c 博主就是
  • QGC 报错 Fail: No CPU load information

    据说是因为bootloader与px4固件版本不匹配 xff0c 需要修改qgc中的参数 xff1a 使其能够在安装固件的时候更新到匹配版本的bootloader 步骤一 xff1a 修改 SDLOG PROFILE 参数从 default
  • Redis复习+面试题

    目录 1 Redis五大数据类型及使用场景 xff1a 1 Redis五大数据类型及使用场景 xff1a String xff1a Redis的字符串是动态字符串 xff0c 内部表示是一个字符数组 xff0c 这里提Python的字符串是
  • 详解大端模式和小端模式

    一 大端模式和小端模式的起源 关于大端小端名词的由来 xff0c 有一个有趣的故事 xff0c 来自于Jonathan Swift的 格利佛游记 xff1a Lilliput和Blefuscu这两个强国在过去的36个月中一直在苦战 战争的原
  • 【c语言数据结构】单链表的基本操作

    一 目的与要求 1 复习C程序调试 运行的基本操作方法 2 熟练掌握编辑 编译 连接和运行C 程序的方法 3 掌握单链表的定义 创建 插入和删除操作程序实现 二 实验内容 1 定义单链表结构体 xff0c 获取数据元素 2 创建链表以输入
  • 【数学建模笔记】【第七讲】多元线性回归分析(二):虚拟变量的设置以及交互项的解释,以及基于Stata的普通回归与标准化回归分析实例

    温馨提示 xff1a 本文共有9683字 xff0c 阅读并理解全文需要半小时左右 一 回归系数的解释 书接上文 xff0c 上文谈到内生性的解决之后 xff0c 我们对回归问题的探究还没有完 比如下面这个问题 xff1a 我们说线性回归他
  • 【番外】Stata软件安装教程

    将下载后的资源解压缩之后双击安装软件 xff1a 点击 下一步 点击 下一步 这里选择第二个 SE 这个选项 xff0c 然后点击 下一步 此处尽量不要修改安装路径 xff0c 尽量使用默认安装路径 然后一直点 下一步 即可 安装完成之后点
  • 【蓝桥杯】【嵌入式组别】第十二节:USART串口通讯

    USART串口通讯 USART xff1a 通用同步异步收发器串口发送程序设计 xff1a 如何连续打印helloworld能不能发送中文 xff1f 串口发送printf重定向 串口接收程序设计 xff1a 串口接收固定长度数据 xff1
  • 【蓝桥杯】【嵌入式组别】第十四节:PWM输出编程

    PWM输出编程 PWM输出原理单路PWM信号输出双路PWM信号输出 目的 xff1a 在特定管脚上产生频率和占空比可调的方波信号 比赛我们主要掌握PA6和PA7就可以了 PWM输出原理 CNT 定时器中的计数器 xff0c 配置成1us增加
  • 【蓝桥杯】【省赛真题】

    关于第十一届第一场蓝桥杯中如何判断串口数据的问题的代码如下 xff1a span class token comment USART span u8 rx buf span class token punctuation span span
  • 【2023年第十三届MathorCup高校数学建模挑战赛】思路总结分析

    写在前面的话 我们选择A题 xff0c 分析A题题目可以得知属于一种组合优化模型 xff0c 类似于旅行商问题 xff0c 0 1背包问题等等 该类问题通常采用遗传算法 xff0c 粒子群算法 xff0c 模拟退火算法等算法进行求解 由于本
  • 【博弈论】【第一章】博弈论导论

    博弈论导论 例题 选择数字 例题 巴什博弈 例题 射手博弈博弈论的基本概念 xff1a 参与人战略行动信息支付函数 例题 分100元 课程概述 xff1a 例题 选择数字 两个参与人A和B xff0c 轮流选择 3 4 5 6 7 8 9
  • C++中的const_interator

    当我们做出如下定义时 vector lt ID gt ids vector lt ID gt const iterator iter 并进行了下面的操作 xff0c 则是正确的 for iter 61 ids begin iter 61 i
  • JAVA基本数据类型的字节与位数以及String类型的最大长度

    目录 基本数据类型的字节与位数如下 xff1a String类型的最大长度 基本数据类型的字节与位数如下 xff1a 变量名称 字节 位数byte 1 8short 2 16int 4 32long 8 64float 4 32double
  • arduino、Ms5611与1602实现气压温度高度显示

    项目场景 xff1a arduino Ms5611与1602实现气压温度高度显示 因为项目需求 xff0c 需要测试Ms5611的精度 xff0c 于是利用arduino和LED1602 xff0c 将Ms5611采集的数据采集并实时显示出
  • UART协议详解

    UART简介 通用异步收发传输器 xff08 Universal Asynchronous Receiver Transmitter xff0c 通常称作UART UART通信在工作中相当常见 xff0c 项目中需要生成uart信号 xff
  • vector的capacity新增长方式(dev c++实测)

    vector的capacity 调用返回vector中最大能够存储的元素个数 xff0c 也即在下一次需要扩充容量之前能容纳的元素个数 reserve会使容器在必要的时候增长 xff0c 以便容纳制指定数目的元素 include lt io
  • Android DNS Resolver

    DNS 解析器 xff08 DNS Resolver xff09 DNS 解析器模块可保护用户免受 DNS 拦截和配置更新攻击 xff0c 并改进了 DNS 解析的网络性能 此模块包含用于实现 DNS 桩解析器的代码 xff0c 该解析器可