鸿蒙网络编程系列5-TCP连接超时分析
1. TCP连接超时简介
TCP是面向连接的协议,通过三次握手建立连接,但是,在建立连接的过程中对方有可能没有响应,这时候发起连接的一方会重试,如果重试多次仍然没有响应,就会触发超时,从而导致连接失败,socket的connect方法支持通过参数设置连接超时时间,默认情况下也可以使用缺省的超时时间,那么,问题来了:
- 连接的默认超时时间是多少?
- 如果超时时间设置为0会怎么样?
- 如果超时时间设置的非常大,比如5分钟,套接字会一直尝试连接吗?
要回答这些问题还不太容易,官方文档也没有给出,下面咱们就自己尝试下,寻找问题的答案。
2.TCP连接超时示例
本示例通过TCP套接字尝试连接一个不存在的IP地址,所以肯定会连接失败,示例中共尝试了5次,第一次使用默认的超时时间,第二次使用0超时时间,第三次使用3秒超时时间,第四次使用30秒超时时间,第五次使用300秒超时时间,每次连接前后都记录下当时的时间,从而方便分析实际耗费的时间。本示例运行后的截图如下所示:

下面详细介绍创建该应用的步骤。
步骤1:创建Empty Ability项目。
步骤2:在module.json5配置文件加上对权限的声明:
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.GET_WIFI_INFO"
}
]
这里分别添加了访问互联网和访问WIFI信息的权限。
步骤3:在Index.ets文件里添加如下的代码:
import socket from '@ohos.net.socket';
import wifiManager from '@ohos.wifiManager';
import systemDateTime from '@ohos.systemDateTime';
//说明:本地的IP地址不是必须知道的,绑定时绑定到IP:0.0.0.0即可,显示本地IP地址的目的是方便对方发送信息过来
//本地IP的数值形式
let ipNum = wifiManager.getIpInfo().ipAddress
//本地IP的字符串形式
let localIp = (ipNum >>> 24) + '.' + (ipNum >> 16 & 0xFF) + '.' + (ipNum >> 8 & 0xFF) + '.' + (ipNum & 0xFF);
@Entry
@Component
struct Index {
//连接、通讯历史记录
@State msgHistory: string = ''
//服务端IP地址
@State serverIp: string = "0.0.0.0"
//服务端端口
@State serverPort: number = 9999
scroller: Scroller = new Scroller()
build() {
Row() {
Column() {
Text("TCP连接超时演示")
.fontSize(14)
.fontWeight(FontWeight.Bold)
.width('100%')
.textAlign(TextAlign.Center)
.padding(10)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("本地IP:")
.width(100)
.fontSize(14)
.flexGrow(0)
Text(localIp)
.width(110)
.fontSize(12)
.flexGrow(0)
}.width('100%')
.padding(5)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("服务端地址:")
.fontSize(14)
.width(90)
.flexGrow(0)
TextInput({ text: this.serverIp })
.onChange((value) => {
this.serverIp = value
})
.width(110)
.fontSize(12)
.flexGrow(1)
Text(":")
.width(5)
.flexGrow(0)
TextInput({ text: this.serverPort.toString() })
.type(InputType.Number)
.onChange((value) => {
this.serverPort = parseInt(value)
})
.fontSize(12)
.flexGrow(0)
.width(60)
}
.width('100%')
.padding(5)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("默认超时时间:")
.fontSize(14)
.width(130)
.flexGrow(0)
Text("default")
.width(110)
.fontSize(12)
.flexGrow(1)
Button("连接测试")
.onClick(() => {
this.connect2Server(true, 0)
})
.width(110)
.fontSize(14)
.flexGrow(0)
}
.width('100%')
.padding(5)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("超时时间为0:")
.fontSize(14)
.width(130)
.flexGrow(0)
Text("0")
.width(110)
.fontSize(12)
.flexGrow(1)
Button("连接测试")
.onClick(() => {
this.connect2Server(false, 0)
})
.width(110)
.fontSize(14)
.flexGrow(0)
}
.width('100%')
.padding(5)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("超时时间为3秒:")
.fontSize(14)
.width(130)
.flexGrow(0)
Text("3000")
.width(110)
.fontSize(12)
.flexGrow(1)
Button("连接测试")
.onClick(() => {
this.connect2Server(false, 3000)
})
.width(110)
.fontSize(14)
.flexGrow(0)
}
.width('100%')
.padding(5)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("超时时间为30秒:")
.fontSize(14)
.width(130)
.flexGrow(0)
Text("30000")
.width(110)
.fontSize(12)
.flexGrow(1)
Button("连接测试")
.onClick(() => {
this.connect2Server(false, 30000)
})
.width(110)
.fontSize(14)
.flexGrow(0)
}
.width('100%')
.padding(5)
Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
Text("超时时间为300秒:")
.fontSize(14)
.width(130)
.flexGrow(0)
Text("300000")
.width(110)
.fontSize(12)
.flexGrow(1)
Button("连接测试")
.onClick(() => {
this.connect2Server(false, 300000)
})
.width(110)
.fontSize(14)
.flexGrow(0)
}
.width('100%')
.padding(5)
Scroll(this.scroller) {
Text(this.msgHistory)
.textAlign(TextAlign.Start)
.padding(5)
.width('100%')
.backgroundColor(0xeeeeee)
}
.align(Alignment.Top)
.backgroundColor(0xeeeeee)
.height(300)
.flexGrow(1)
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.On)
.scrollBarWidth(20)
}
.width('100%')
.justifyContent(FlexAlign.Start)
.height('100%')
.padding(5)
}
.height('100%')
}
//连接服务端
async connect2Server(defaultTimeout: boolean, timeout: number) {
//执行TCP通讯的对象
let tcpSocket = socket.constructTCPSocketInstance();
let localAddress = { address: "0.0.0.0", family: 1 }
await tcpSocket.bind(localAddress)
//服务端地址
let serverAddress = { address: this.serverIp, port: this.serverPort, family: 1 }
let option: socket.TCPConnectOptions = { address: serverAddress }
if (!defaultTimeout) {
option = { address: serverAddress, timeout: timeout }
this.msgHistory += "连接超时时间设置:" + timeout.toString() + "\r\n";
} else {
this.msgHistory += "连接超时时间设置:default" + "\r\n";
}
this.msgHistory += "连接开始时间:" + await getCurrentTimeString() + "\r\n";
await tcpSocket.connect(option)
.then(() => {
this.msgHistory += 'connect success ' + "\r\n";
})
.catch(async (e) => {
this.msgHistory += 'connect fail ' + e.message + "\r\n";
this.msgHistory += "连接结束时间:" + await getCurrentTimeString() + "\r\n\r\n";
})
await tcpSocket.close()
}
}
//同步获取当前时间的字符串形式
async function getCurrentTimeString() {
let time = ""
await systemDateTime.getDate().then(
(date) => {
time = date.getHours().toString() + ":" + date.getMinutes().toString()
+ ":" + date.getSeconds().toString() + ":" + date.getMilliseconds().toString()
}
)
return "[" + time + "]"
}
步骤4:编译运行,可以使用模拟器或者真机。
步骤5:配置服务端IP和端口,一定要设置不存在的地址,然后逐次单击“连接测试”按钮,执行后的截图如下所示:

截图的最后是连接日志信息:

3.TCP连接超时分析
从输出的日志可以分析如下:
1.默认的超时时间为5秒钟
2.超时时间设置为0时,按照5秒钟计算超时时间
3.设置3秒钟或者30秒钟,实际超时时间就是3秒钟或者30秒钟
4.设置大于65秒的超时时间,实际超时时间为65秒左右
前3个好理解,最后这个65秒是怎么回事呢?这里分析一下,实际上,TCP连接重试时执行等待时间翻倍的规则,也就是连接失败后等待1秒钟重试,再失败等待2秒钟,然后依次是4秒钟、8秒钟、16秒钟、32秒钟,linux默认重试5次,也就是1+2+4+8+16+32=63秒钟,再加上其他耗费的时间,所以表现出来最大超时时间是65秒左右。
怎么样,是不是对鸿蒙系统下TCP连接超时时间有了更清晰的认识呢?
(本文作者原创,除非明确授权禁止转载)
本文码云源码地址:https://gitee.com/zl3624/harmonyos_network_samples/tree/master/code/tcp/TCPTimeoutDemo
本系列码云源码地址:
https://gitee.com/zl3624/harmonyos_network_samples
相关文章:
鸿蒙网络编程系列5-TCP连接超时分析
1. TCP连接超时简介 TCP是面向连接的协议,通过三次握手建立连接,但是,在建立连接的过程中对方有可能没有响应,这时候发起连接的一方会重试,如果重试多次仍然没有响应,就会触发超时,从而导致连接…...
金蝶云星空移动字段后关闭页面后重新打开无效
有同事反馈,单据的明细字段里面移动了字段,然后退出,其他字段都能按最后排版的位置显示,有个别字段始终无法按照排版的位置显示。 只需要打开BOS平台,找到对应字段,然后更改可见性。...
幂律分布笔记
一、幂律分布的数据拟合 数据分箱: 所谓分箱就是对原始数据进行分组,然后对每一组内的数据进行平滑处理。常见的分箱方式主要有等深分箱、等宽分箱、用户自定义等 对数分箱: 对原数据进行分箱,第i个箱的宽度为bi,b…...
一些NLP代表性模型
(一)BERT 由Bidirectional Encoder Representations from Transformers的首字母组成,是encoder-only结构类型的代表。 模型分预训练和微调两步,预训练任务有两类:masked language model(MLM)、next sentence predict…...
低代码移动端开发:未来的趋势与挑战
什么是低代码移动端开发? 低代码移动端开发平台允许开发者通过可视化界面和少量编码来构建应用程序。相较于传统的代码开发,低代码平台大大降低了技术和学习门槛,使非专业开发人员也能参与到移动应用的开发过程中。 低代码移动端开发的优势 …...
【Linux】嵌入式Linux系统的组成、u-boot编译
Linux—嵌入式Linux系统的组成、u-boot编译 前言一、嵌入式Linux系统的组成1.1 嵌入式Linux系统和PC完整的操作系统的对比如下:1.2 PC机—Windows系统启动流程(PC机—Linux系统、嵌入式ARM—linux系统的启动流程类似) 二、编译u-boot2.1 u-bo…...
Qt打开excel文件,并读取指定单元格数据
1. 下载并安装QXlsx库,详见之前的博文Qt子线程创建excel文件报错QObject: Cannot create children for a parent that is in a different thread.-CSDN博客 2. // 创建一个XlsxDocument对象QString filename "D:\\mydocuments\\data_acquisition\\data\\tes…...
适合下班回家做的小副业,用AI做视频,几天时间3000+
大家好,今天要给大家分享的项目是定制儿歌,精准定位宝妈群体,每天轻松赚500! ***01* 项目原理 父母都非常疼爱自己的孩子,愿意为孩子提供独特的东西。而我们正是利用这一点,通过免费AI工具生成专属的儿童…...
git的基本操作 + 分支管理
一、基本操作 1. 修改文件 Git比其他的版本管理器设计得更加优秀,因为Git追踪并管理的是修改,而非文件。 修改一个文件,不管你是添加一行,或者删除一行,还是添加了又删除了,甚至你创建了一个新文件&…...
VRRP
1、VRRP简介 虚拟路由冗余协议 VRRP(Virtual Router Redundancy Protocol)通过把几台路由设备联合组成一台虚拟的路由设备,将虚拟路由设备的IP地址作为用户的默认网关实现与外部网络通信。当网关设备发生故障时(单点故障…...
个人健康系统|个人健康数据管理系统|基于小程序+java的个人健康数据管理系统设计与实现(源码+数据库+文档)
个人健康数据管理系统 目录 基于小程序java的个人健康数据管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布道师…...
R语言统计分析——折线图
参考资料:R语言实战【第2版】 如果将散点图上的点从左到右连接起来,就会得到一个折线图。以基础安装中的Orange数据集为例,展示如下: # 设置绘图参数 opar<-par(no.readonly TRUE) # 画布拆分为1行2列 par(mfrowc(1,2)) # 选…...
前端怎么实现电子签名
电子签名(e-signature)作为一种数字化的签署方式,广泛应用于合同、协议等文件的确认中。随着科技的发展,前端技术也为电子签名的实现提供了便利。本文将探讨在前端如何实现电子签名,包括技术选型、实现步骤及注意事项。…...
数字后端零基础入门系列 | Innovus零基础LAB学习Day1
一 Floorplan 数字IC后端设计如何从零基础快速入门?(内附数字IC后端学习视频) Lab5-1这个lab学习目标很明确——启动Innovus工具并完成设计的导入。 在进入lab之前,我们需要进入我们的FPR工作目录。 其中ic062为个人服务器账户。比如你端…...
鼠标移入盒子,盒子跟随鼠标移动
demo效果: 鼠标移入盒子,按下鼠标,开启移动跟随移动模式,再次按下关闭移动模式 涉及主要属性 在元素上单击鼠标按钮时输出鼠标指针的坐标: var x event.pageX; // 获取水平坐标 var y event.pageY; // 获取垂直坐标元素offsetL…...
css的简单问题
1.display:none;和visibility:hidden;的区别 相同点:都可以让元素不可见 区别: display:none;可以让元素完成在渲染树中消失,渲染时不占任何空间;visibility:hidden;不会让元素从渲染树消失,渲染元素继续占据空间&a…...
使⽤ Override 和 New 关键字进⾏版本控制(C#)
文章目录 1. 基础概念1.1 override1.2 new 2. 示例代码1. override 关键字2. new 关键字 3.完整示例测试3.1 基类和派生类的定义3.2 测试代码3.3 运行结果 结论 在 C# 中,override 和 new 关键字用于控制类之间的成员方法的隐藏和重写。理解它们之间的差异和使用场景…...
JavaScript 15章:模块化编程
在现代软件开发中,模块化编程是一种非常重要的实践,它可以帮助开发者组织代码,提高代码的复用性和可维护性。以下是关于模块化编程的一些关键知识点和实战案例: 第15章:模块化编程 模块的概念 模块是指将一组相关的…...
qt creator 开发环境的安装
1.找官网 官网地址:Installation | Qt Creator Documentation 点 Parent Directory 继续点 Parent Directory 点 archive/ 2.下载在线安装器 点 online_ainstallers 选择在线安装器版本 选择对应版本后进入下载列表,根据自己的系统选择下载。 下载后…...
Xilinx远程固件升级(二)——STARTUPE2原语的使用
通过(一)可以看出,对于远程固件升级实际上是通过调用flash不同区域的bit实现,通过golden image和update image共同保障了系统的稳定性。在项目中如果将flash的时钟直接绑定FPGA后进行约束,在综合编译时是无法通过的。这…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
SQL注入篇-sqlmap的配置和使用
在之前的皮卡丘靶场第五期SQL注入的内容中我们谈到了sqlmap,但是由于很多朋友看不了解命令行格式,所以是纯手动获取数据库信息的 接下来我们就用sqlmap来进行皮卡丘靶场的sql注入学习,链接:https://wwhc.lanzoue.com/ifJY32ybh6vc…...
