news 2026/11/3 12:26:31

Android TCP网络通信前置配置:权限、明文流量与线程模型全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android TCP网络通信前置配置:权限、明文流量与线程模型全解析

做Android开发久了就会知道,TCP网络通信本身并不难,难的其实是把它跑通之前那一大堆前置配置。很多新手第一次写Socket连接,代码抄得一字不差,编译也通过了,结果一装到真机上就报错——不是权限没声明,就是明文流量被系统拦了,再不然就是主线程直接抛NetworkOnMainThreadException。这三个坑我当年都踩过,而且是轮流踩,一个坑爬出来掉进另一个坑。后来带过几个新人,发现他们走的弯路几乎一模一样。

这篇就专门聊透“Android APP实现TCP网络通信的前提配置”这件事。我会把权限怎么声明、明文流量怎么放行、线程模型怎么绕开,以及连接超时怎么定位,全部分开讲清楚,最后给出一套完整的最小化Demo参考。不管你是刚接触Android网络编程,还是已经写过HTTP接口但第一次碰TCP长连接,这篇文章都能帮你少走一截弯路。

1. 为什么TCP通信这么麻烦:前置配置的必要性

1.1 看似只是一小段代码,为什么配置一堆

很多初学者会有个疑问:我在电脑上写Java TCP Socket通信,十几行代码就通了,到了Android上怎么就这么多讲究?这其实是Android的定位决定的。它是跑在移动设备上的系统,面临的威胁远比桌面电脑复杂。一个APP如果随随便便就能建立网络连接、读取设备信息、发送数据,那用户装一个恶意应用,隐私基本就全裸奔了。所以Android从两个维度做了限制:一是权限声明,你要用某项能力就必须在Manifest里写清楚;二是进程隔离与安全策略,应用默认跑在沙箱里,连网、读写存储、访问通讯录都需要显式授权。

TCP网络通信涉及网络权限、主线程策略、明文流量策略、网络状态检测这几个层面,每一层都是一道关卡。HTTP请求因为链路短、请求响应模式简单,很多框架(比如OkHttp、Retrofit)已经在内部帮你绕开了部分限制,所以你会觉得HTTP没这么麻烦。但TCP Socket是你自己在原生层操作,所有限定条件都必须自己处理。这就是为什么“前提配置”这件事值得单独拿出来讲,因为它决定了你后面代码能不能跑起来。

另外还要注意一点,Android系统版本本身也在不断收紧。早期版本(API 27及以下)默认允许明文流量,开发者随便写都能跑;到了Android 9(API 28)明确了默认阻断所有明文HTTP/TCP流量,很多老项目的代码一夜之间就“失灵”了。如果你的APP要适配不同版本的设备,配置就必须考虑到这一层兼容问题,这也是前置配置绕不开的原因之一。

1.2 前置配置清单:一张表看清要搞定哪些事

我根据实际开发经验,把所有跟TCP通信相关的前置条件整理成了一张表。你可以先收藏,后面每一节会展开讲。

配置项作用影响范围
INTERNET权限允许应用访问网络API 1至今都必需
ACCESS_NETWORK_STATE权限允许读取当前网络状态用于断线检测与重连策略
usesCleartextTraffic允许使用明文流量(HTTP/TCP)API 28及以上默认关闭
网络安全配置XML灵活指定可明文访问的目标替代全局开关,更精细
主线程网络操作限制禁止在UI线程执行网络请求Android 4.0(API 14)起强制
连接超时设置避免连接失败后无响应代码层必须显式设置

这六项里,前四项属于“能不能连”的问题,后两项属于“连得稳不稳”的问题。很多人只管前四项,觉得能连通就完事了,结果APP跑在弱网环境下直接卡死或崩溃,这就是没把后两项当回事。

2. 网络权限配置的写法与常见误区

2.1 INTERNET权限:一句最基础也最关键的话

所有需要联网的Android应用,第一步都是在AndroidManifest.xml里添加权限声明。这行代码放在<manifest>节点下、<application>节点上方:

<uses-permission android:name="android.permission.INTERNET" />

它属于normal级别的权限,系统会在安装时自动授予,不需要像相机、定位那样在运行时弹窗申请。这一点很多从Android 6.0动态权限时代过来的开发者容易搞混,以为凡是权限都要在代码里动态申请。这里明确说:INTERNET权限不需要运行时申请,也不需要任何额外处理,只要Manifest里写了就行。

但“写了就行”这件事有个隐蔽的坑——如果你在Android Studio的新工程模板里手动改了包名,或者使用了多个Module的项目,权限容易加错位置。我就遇到过一整个项目编译都正常,但子Module里的代码始终报Permission denied的问题,检查了半天,发现是权限加了子Module的Manifest里,而主Module的清单文件里没有合并进来。多Module项目里最好在主Module的AndroidManifest.xml里声明网络权限,同时确认manifestPlaceholders没有导致清单合并异常。

2.2 ACCESS_NETWORK_STATE:检测网络状态的前提

如果你只是写一个简单的TCP客户端,只加INTERNET权限理论上就能跑通。但如果你要做的连接稳定性相关的功能——监听网络切换、WiFi断开自动重连、飞行模式检测——那就还需要另一个权限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

这个权限让应用能够读取当前网络的连接状态和类型。实际场景里,我建议无论你的TCP通信逻辑多简单,都把这个权限一并加上。因为后面调试时你一定会遇到“连不上服务器”的情况,到时候第一个要确认的就是设备当前到底有没有网。没有这个权限,你连ConnectivityManager的getActiveNetworkInfo()都调不出来,排查问题直接少了一条路。

我自己写过的一个物联网项目就是典型例子。设备连上WiFi后TCP服务器偶尔踢掉连接,如果APP不能准确感知网络状态变化,就只能在错误回调里干等。后来加了ACCESS_NETWORK_STATE权限,配合NetworkCallback监听网络变化,重连成功率从不到七成提升到接近满状态。这个权限看起来不起眼,但在实际调优里价值很大。

2.3 一个常见的误区:动态权限申请与网络权限

我记得技术社区里有个提问很典型——代码里已经requestPermissions申请了INTERNET权限,为什么还是SocketException: Permission denied?

这里要讲清楚一个底层逻辑:Android的权限体系分为安装时权限和运行时权限。INTERNET、ACCESS_NETWORK_STATE、ACCESS_WIFI_STATE这类normal权限属于安装时权限,系统安装APK时就完成了授权,代码里再申请一次也不会弹窗,系统会直接返回PERMISSION_GRANTED,但这并不会让它“更有效”。如果你真的遇到了Permission denied,绝大多数情况是Manifest里没有声明,或者声明了但目标SDK版本对应的清单合并出了问题,而不是因为你没在代码里申请。

还有一个小细节:如果你的应用targetSdkVersion是31或更高,并且你的TCP连接需要访问本机网络接口信息(比如获取本机IP),可能还需要android.permission.INTERNET和ACCESS_NETWORK_STATE以外的一些接口感知权限。不过绝大多数纯TCP客户端不会用到,这里不展开。

3. 明文流量策略:Android 9之后最容易被卡的一关

3.1 从一个大坑说起:一切正常,就是不连服务器

我接手的第一个TCP项目,当时测试机和服务器都在内网,服务器IP是类似192.168.x.x这种私有地址,通信协议用的是最原始的Socket+DataOutputStream。代码逻辑完全没问题——我在PC上新建了同样的Java工程,同样的IP、同样的端口,几秒钟就把数据发出去了。但是在Android上,连接一直抛异常,日志显示java.net.ConnectException,看起来像连接失败。我当时差点开始怀疑是不是防火墙问题。

后来仔细看了日志,才发现真正的报错在更早的地方:CLEARTEXT communication to 192.168.1.100 not permitted by network security policy。

这就是明文流量策略拦截。Android 9开始,系统默认禁止所有应用使用明文协议(HTTP、TCP)进行通信。但很多老项目用的服务器就是明文TCP,没有走TLS,所以必须显式告诉系统“这个目标地址允许明文访问”,否则你怎么折腾都连不上。

3.2 解决方案一:全局允许明文流量

最直接的方式,在<application>节点上添加一个属性:

<application android:usesCleartextTraffic="true"> </application>

一行代码,全局生效。开发阶段图省事,我一般直接用这个。但要意识到,这等于告诉系统这个应用可以跟任意地址建立明文连接,安全隐患是存在的。如果你的APP涉及用户敏感数据,或者要上架商店,最好不要用这种方式,尤其是正式包。

另外要提醒一点:android:usesCleartextTraffic="true"只影响APP自身发起的连接。如果你的APP通过WebView加载了某个明文HTTP页面,这两个机制不互相覆盖,usesCleartextTraffic对WebView同样生效,但WebView内部是否允许混合内容还有自己的一套策略。不要搞混。

3.3 解决方案二:网络安全配置,只放行特定域名或IP

更细致的办法是使用Network Security Config。先在res/xml目录下新建一个文件,例如network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="false" /> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">example.com</domain> <domain includeSubdomains="true">192.168.1.100</domain> </domain-config> </network-security-config>

然后Manifest里引用它:

<application android:networkSecurityConfig="@xml/network_security_config"> </application>

这种方式的优势是精确。你只对需要明文通信的内网服务器或特定测试域名放行,其余地址仍然保持系统默认的阻断策略。我负责过的一个物流项目就是用的这个方案——仓库里的几台扫码设备需要连接本地TCP服务器,但APP本身也会访问公网的HTTPS接口。如果全局放行明文流量,风险太大;用domain-config精确控制,公网通信不受影响,内网TCP又正常,两边都照顾到了。

有个实际经验想分享:domain标签里写IP地址是可以的,但要注意,如果服务器后来换了IP,配置就得跟着改。此外,TCP通信如果走域名,建议includeSubdomains设为true,因为有些服务器内部会做域名跳转,例如从api.example.com跳转到data.example.com,如果没包含子域名,跳转后的连接照样会被拦。

3.4 目标SDK版本对明文策略的影响

明确一个容易混淆的点:usesCleartextTraffic和targetSdkVersion的关系。

  • 如果targetSdkVersion在27及以下,系统默认允许明文流量,你不需要任何配置就能跑TCP。
  • 如果targetSdkVersion是28及以上,系统默认拒绝明文流量,必须显式配置才能放行。

我的建议是:不管你的targetSdkVersion是多少,只要涉及TCP明文通信,都主动做好网络安全配置。因为设备上运行的是用户手机的真实系统版本,不是你编译时的SDK版本。手机系统是Android 12、13、14这些版本时,就算你的targetSdkVersion是26,市场上很多ROM也会额外收紧明文流量策略,不配置照样连不上。

3.5 双栈环境的补充:IPv6与IPv4的处理背景

另一个容易被忽略的背景是服务器同时监听IPv4和IPv6的情况。现在的Android设备在WiFi网络下经常默认拿到IPv6地址,如果你在代码里用域名建连(而不是直接写死IP地址),解析时可能优先走IPv6。如果服务器只监听了IPv4,TCP三次握手的SYN包就得不到回应,表现就是连接超时。

这种问题通常和前置配置无关——不是权限、也不是明文策略,而是DNS解析与目标服务器协议栈的兼容性。排查思路是在代码里分别尝试IPv4和IPv6的InetAddress,或者直接让服务器把IPv6也监听起来。这个点先记在这里,后面排查部分还会提到。

4. 主线程限制与网络线程模型:最容易踩的运行时崩溃

4.1 为什么不能在主线程里写Socket连接

Android有一个极其严格的设计原则:所有UI操作必须在主线程(UI线程)完成,而所有耗时操作禁止在主线程执行。网络请求当然属于耗时操作,所以只要你在主线程直接写:

Socket socket = new Socket("192.168.1.100", 8080);

运行后几乎立刻就会看到:

android.os.NetworkOnMainThreadException

这个异常是Android 4.0(API 14)以后引入的,目的很明确——防止APP因为网络阻塞导致界面卡死。如果你在主线程同步执行一次TCP连接,连接过程可能耗时几秒甚至几十秒,用户看到的就是一个无法操作的冻结界面,体验极差。所以系统的做法是直接拒绝:你敢在主线程阻塞,我就敢立刻给你抛异常。

很多初学者会问:那我用new Thread不就行了?对,这是最简单的解决办法,但只是一个起点。后面你还会遇到线程间通信的问题——比如子线程里收到服务器数据了,怎么更新UI?这就涉及到runOnUiThread、Handler等机制。如果你用的是Kotlin协程,处理起来会优雅很多,但底层逻辑是一样的:网络操作必须离开主线程,数据回调回主线程更新UI。

4.2 线程模型方案怎么选:Thread、线程池、协程

下面我根据自己的经验简单对比一下三种常见方案,帮你按需选择。

方案一:直接new Thread

new Thread(new Runnable() { @Override public void run() { // TCP连接与数据收发 } }).start();

适合写Demo或临时验证,不做生产建议。每次连接都新建线程,线程数多时系统负担大、管理混乱。

方案二:线程池

ExecutorService executor = Executors.newFixedThreadPool(4); executor.execute(new Runnable() { @Override public void run() { // TCP连接与数据收发 } });

适合一个项目里需要管理多条TCP连接、或者连接频繁建立的场景。线程池复用线程,避免无限创建的性能浪费。

方案三:Kotlin协程

lifecycleScope.launch(Dispatchers.IO) { val socket = Socket() socket.connect(InetSocketAddress(host, port), 3000) // 收发数据 }

这是目前我主力推荐的方式。协程可以在IO调度器上执行阻塞式网络操作,代码写起来跟同步一样直观,退出页面时还能通过lifecycleScope自动取消,避免协程泄漏。但要注意,协程本身不解决NetworkOnMainThreadException,你必须显式切到Dispatchers.IO或Default,否则在Main上执行Socket照样抛异常。

最重要的是,不管选哪个线程方案,都要记住一个原则:连接操作用异步,数据回调回主线程更新UI。这个原则能覆盖90%以上的TCP通信场景。

4.3 连接超时的处理:不设置等于定时炸弹

TCP连接代码里有一行很多人会忽略:

Socket socket = new Socket(); socket.connect(new InetSocketAddress("192.168.1.100", 8080), 3000);

注意看,这个connect方法带第二个参数timeout,单位是毫秒。如果你写成:

Socket socket = new Socket("192.168.1.100", 8080);

系统会使用默认超时——在很多设备上可能长达几十秒甚至一分钟。在弱网环境下,TCP握手一直得不到服务器响应,你的线程就会一直阻塞在那里。如果这个线程还有多个,或者涉及重连逻辑,APP就会表现为卡顿、ANR、甚至OOM。

我的习惯是所有TCP连接都显式设置超时。根据业务场景不同,内网连接我给3-5秒,公网连接给8-10秒。超时后抛出SocketTimeoutException,再走重连策略或报错回调。这个参数放在前置配置里讲,是因为它直接决定你的APP能不能在弱网环境下正常存活。

5. 完整实操流程:从新建项目到连通TCP服务器

5.1 环境准备与版本确认

我平时新建验证工程时,会按这套流程走一遍,你也可以直接参照。

第一步,Android Studio里新建Project,建议选择Empty Activity模板。注意记录一下自动生成的targetSdkVersion——如果高于28,后面明文流量配置就必不可少。

第二步,打开AndroidManifest.xml,在<manifest>节点下添加两个权限:

<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

第三步,在<application>节点上,按需添加明文流量配置。如果服务器是HTTPS或TLS加密的TCP,不需要;如果是明文TCP,添加:

<application android:usesCleartextTraffic="true"> </application>

或者按照3.3节的方式,新建res/xml/network_security_config.xml并引用。

这三步做完,前置配置就基本齐了。剩下的是代码层面的线程与超时处理。

5.2 最小化TCP客户端参考Demo

我提供一个最简单的TCP客户端参考代码,以Java为例,方便直接复制跑通:

public class TcpClient { private static final String HOST = "192.168.1.100"; private static final int PORT = 8080; private static final int TIMEOUT = 5000; public static void connectAndSend(final String message) { new Thread(new Runnable() { @Override public void run() { Socket socket = null; try { socket = new Socket(); socket.connect(new InetSocketAddress(HOST, PORT), TIMEOUT); OutputStream os = socket.getOutputStream(); os.write(message.getBytes("UTF-8")); os.flush(); InputStream is = socket.getInputStream(); byte[] buffer = new byte[1024]; int len = is.read(buffer); if (len != -1) { String response = new String(buffer, 0, len, "UTF-8"); runOnUiThread(() -> tvResult.setText("收到服务器响应:" + response)); } } catch (SocketTimeoutException e) { Log.e("TcpClient", "连接超时", e); } catch (IOException e) { Log.e("TcpClient", "连接失败", e); } finally { try { if (socket != null) { socket.close(); } } catch (IOException e) { Log.e("TcpClient", "关闭Socket失败", e); } } } }).start(); } }

这段代码的关键点我已经标出来了:显式设置连接超时、异常分离处理、finally里关闭Socket防止资源泄漏。你可以在一个按钮的点击事件里调用connectAndSend,就能在Android设备上跑通一次完整的TCP请求-响应流程。

如果要升级成可靠的生产代码,还需要补几块。一是心跳机制——长连接场景下服务器如果一段时间没收到数据就会断开,客户端需要定时发送心跳包。二是断线重连——用指数退避策略,比如第一次失败等1秒重试,第二次等2秒,第三次等4秒,不要无脑死循环重连。三是拆包粘包处理——TCP是字节流,没有消息边界,如果你的协议不是一行一个消息,就需要自己定义长度字段或分隔符。这些属于进阶话题,本文不展开,但你要有意识。

5.3 保障连接稳定性的几个附加配置

既然是聊“前提配置”,我再补充几个容易忽略的附加项。

android:usesCleartextTraffic或网络安全配置解决的是能不能连的问题,但连接持续期间,Android还有一些机制可能主动断开你的Socket,最典型的是WiFi休眠策略和Doze模式。如果APP在后台运行、屏幕熄灭,系统可能会休眠WiFi模块,导致TCP连接被静默断开。如果你需要长时间保持连接,有几个做法可以参考:

  • 使用前台服务(Foreground Service)维持进程优先级,降低被系统回收的概率
  • 申请WAKE_LOCK不是推荐做法,因为它耗电严重,一般只建议在特殊场景使用
  • 利用NetworkCallback监听网络连接变化,网络恢复后主动执行重连
  • 实现心跳包机制,定期发送应用层心跳,既能探测连接是否有效,也能防止NAT超时踢掉映射

这几项其实不完全算“前置”,很多开发者会在接入阶段就一起设计好。为了不让你后面抓瞎,我在这里提前提个醒。

5.4 在Android 14等新版本上的兼容性说明

如果你的测试机系统版本比较新,前置配置还需要多留一个心眼。Android 14及更高版本对网络安全策略的管控更细,比如完全限制了targetSdkVersion较低的应用安装(这属于系统层面的政策,但会影响你的测试装包)。在开发阶段,如果你发现APP安装了但连不上任何网络,先看看是不是目标SDK版本与系统要求的兼容性出了问题。

近年Android版本还有一个趋势是更严格的权限透明化——网络权限倒是没有变化,但后台联网行为会更受限制,系统会在权限页面展示“后台联网权限”,部分国产品牌ROM甚至会默认禁止应用后台联网。测试时如果发现前台连接正常、后台就断,先检查系统设置里的联网控制。

6. 常见问题与排查技巧实录

6.1 权限配置了却仍然没有网络权限

现象:Manifest里明明写了INTERNET权限,编译运行不报错,但连接时抛出SecurityException: Permission denied (missing INTERNET permission?)。

排查步骤:

第一步,确认权限是在哪个Module的Manifest里。多Module项目里,主Module和library的Manifest会合并,但有些情况下子Module的权限并不会生效到主工程。用Android Studio打开Project Structure,或者直接看AndroidManifest.xml的Merged Manifest标签页,搜索INTERNET是否出现在合并清单中。

第二步,检查是否有tools:node="remove"之类的清除操作。如果你使用了高版本的Manifest合并策略,某些依赖库可能定义了tools:node="remove",把网络权限从最终合并结果里干掉了。这种情况非常隐蔽,我在一个第三方SDK集成就遇到过。

第三步,确认测试设备是否开启了“限制后台网络”,部分定制ROM在省电模式或流量节省模式下会阻止应用联网,表现与Permission denied类似。

注意:INTERNET权限是normal级别,安装后即为“始终允许”状态。系统设置里的联网控制如果关闭了,即使Manifest正确也会失败。

6.2 明文流量配置后仍然无法连接

现象:usesCleartextTraffic已经设置为true,但TCP连接仍然报Cleartext communication not permitted。

这种情况我在项目中遇到过两次,最后定位是两个原因:

一是networkSecurityConfig和usesCleartextTraffic同时存在时的优先级问题。如果你在Manifest里同时写了android:networkSecurityConfig和android:usesCleartextTraffic="true",某些系统版本会优先读取networkSecurityConfig,而你的配置文件里又写了<base-config cleartextTrafficPermitted="false" />,那全局开关就被覆盖了。解决办法是只保留一种配置方式,不要混用。

二是个别Android版本把配置缓存住了,改完Manifest后没有彻底清理。特别是某些国产ROM的优化策略,会缓存应用的安全配置。解决方法是卸载APP、清理缓存后重新安装,而不是直接覆盖安装。覆盖安装时旧配置残留,你改的配置可能不会生效。

6.3 连接超时的背后不一定是配置问题

如果你已经确认权限、明文配置都没问题,但TCP连接始终超时,我不建议继续折腾Manifest了。这时候大概率是网络环境因素:

  • 服务器IP和端口在测试设备上能不能通?用PC在同一个网络下telnet验证一下,先排除服务器侧问题
  • 手机和服务器是否在同一网段?跨网段可能被防火墙拦住
  • 运营商网络是否封禁了高端口?有些移动网络对常用端口以外的入站连接有限制
  • IPv6/IPv4双栈问题,前面已经提过——确认服务器监听在哪个协议栈上

我踩过最隐蔽的一个坑,是公司办公WiFi开了“访客隔离”,同一WiFi下的设备互访被阻断。当时还以为是手机系统配置有问题,折腾了大半天,最后拿手机开热点连上测试服务器,秒通。这个案例说明,排查问题时要先在逻辑上分层:App配置一关,服务器状态一关,网络环境一关,逐关排除,而不是盯着Manifest死磕。

6.4 常见问题速查表

问题现象大概率原因解决办法
SocketException: Permission deniedManifest缺少INTERNET或合并异常检查合并清单,确认权限有效
Cleartext communication not permitted明文流量被系统策略拦截添加usesCleartextTraffic或networkSecurityConfig
NetworkOnMainThreadException主线程直接执行网络操作切到子线程/协程IO调度器
ConnectException: Connection refused服务器未监听或防火墙拦截用PC工具验证端口通断
SocketTimeoutException服务器响应慢或网络不通增大超时值,同时检查路由与防火墙
能连通但数据读不到协议格式不匹配或拆包粘包抓包分析,按协议规范解析字节流
后台一段时间后连接断开NAT超时或系统休眠心跳机制+前台服务+断线重连

6.5 一个值得养成的调试习惯:用抓包工具确认问题边界

最后分享一个我很受用的习惯。前置配置不管怎么检查,都只是“纸面配置”正确,实际走不走得通,最好用抓包工具(比如Wireshark)看TCP握手包来确认。

真机连接服务器时,如果在抓包软件里看到SYN包发出去了,但一直收不到SYN-ACK,问题基本在网络路径上——服务器防火墙、路由策略、云安全组都在这个范畴。如果SYN包根本没发出来,那问题还在APP本地,需要继续查权限和配置。

这个习惯帮我节省了大量排查时间。它的本质是把问题从“代码对不对”和“配置对不对”中抽离出来,直接看网络层面的真相。很多时候定位问题不一定靠加日志,抓包看协议交互就够了——尤其是TCP这种有明确三次握手过程的协议,包一级的观察结果几乎不会骗人。

说到个人体会,我做了几年Android网络开发,最大的感受是TCP通信本身是“标准化”的,难点永远在周边这一圈环境上——权限、策略、线程、网络链路。前置配置看起来是些琐碎小事,但每一样都决定着你后续代码能不能正常工作。把这几个约束条件想清楚,TCP在你的Android项目里就不再是一个玄学问题了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 6:25:33

独角戏破圈实战拆解:从选题到舞台表演的完整方法论

第三届国际独角戏剧节颁奖那晚&#xff0c;最佳女演员的结果一出&#xff0c;台下没什么争议&#xff0c;朋友圈倒是先炸开了。《北去南归》的女主演捧着奖杯&#xff0c;另一只手还握着那根贯穿全剧的行李箱拉杆&#xff0c;这一幕被摄影师抓下来&#xff0c;成了那晚传播最广…

作者头像 李华
网站建设 2026/11/2 21:55:38

接口测试传参用到的空字符串的错误处理

在做接口测试时&#xff0c;接口请求参数用占位符来替换&#xff0c;但是因为代码的错误处理会带来错误的参数传递。具体是这样的&#xff0c;传参是username&password*{password3}, 写了个变量替换方法def regi_var_substitute(params):#10132026 要注意&#xff1a;当参数…

作者头像 李华
网站建设 2026/11/3 6:40:59

SSM学校食堂管理系统:Spring+SpringMVC+MyBatis实战项目源码解析

你有没有见过学校食堂饭点排长队的场面&#xff1f;窗口前里三层外三层&#xff0c;刷卡机前挤成一团&#xff0c;打饭阿姨一边打菜还要一边盯着账目&#xff0c;漏记错记时有发生。这种混乱背后&#xff0c;往往不是师傅手脚慢&#xff0c;而是整个食堂缺乏一套清晰的信息化管…

作者头像 李华
网站建设 2026/10/25 1:28:54

【单片机课设毕设项目】基于单片机的婴儿床哭泣尿床PM2.5监测与联动系统设计 基于WIFI的智能婴儿监护环境监测与远程提醒装置设计(032706)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/10/25 7:02:11

图像频域处理实战:从傅里叶变换到频谱滤波的工程落地

1. 这不是数学课&#xff0c;是图像处理的“透视眼”训练手册你有没有试过把一张模糊的照片拉到最大&#xff0c;想看清车牌号或人脸细节&#xff0c;结果只看到一片马赛克&#xff1f;或者在修图软件里调“锐化”滑块时&#xff0c;明明拉高了却让边缘泛起奇怪的白边&#xff…

作者头像 李华