戴新军 發表於 2026-2-18 08:01:00

生产环境易语言网络通信编程基础:HTTP/HTTPS/TCP/UDP实战开发最佳实践与性能优化

<style>pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; line-height: 1.6 !important; padding: 16px !important; margin: 16px 0 !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; tab-size: 4 !important; -moz-tab-size: 4 !important; max-width: 100% !important; box-sizing: border-box !important }
code { font-family: "Consolas", "Monaco", "Courier New", monospace !important; font-size: 14px !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; overflow-wrap: normal !important; display: inline !important; background: rgba(0, 0, 0, 0) !important; border: none !important; padding: 0 !important; margin: 0 !important; line-height: inherit !important }
pre code { background: rgba(0, 0, 0, 0) !important; border: 0 !important; border-radius: 0 !important; display: block !important; line-height: 1.6 !important; margin: 0 !important; max-width: none !important; overflow: visible !important; padding: 0 !important; white-space: pre !important; word-wrap: normal !important; word-break: normal !important; color: inherit !important }
.token.comment, .token.prolog, .token.doctype, .token.cdata { color: rgba(112, 128, 144, 1) !important; font-style: italic !important }
.token.punctuation { color: rgba(153, 153, 153, 1) !important }
.token.atrule, .token.attr-value, .token.keyword { color: rgba(0, 119, 170, 1) !important; font-weight: bold !important }
.token.function, .token.class-name { color: rgba(221, 74, 104, 1) !important; font-weight: bold !important }
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted { color: rgba(102, 153, 0, 1) !important }
.token.property, .token.tag, .token.boolean, .token.number, .token.constant, .token.symbol, .token.deleted { color: rgba(153, 0, 85, 1) !important }
.cnblogs-markdown pre, .cnblogs-post-body pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; background-color: rgba(248, 248, 248, 1) !important; border: 1px solid rgba(225, 228, 232, 1) !important; border-radius: 6px !important; padding: 16px !important; margin: 16px 0 !important }
pre, pre, pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important }</style>
      <blockquote><p>上周在生产环境遇到了这个问题,排查了2天才定位到原因。今天分享一下完整的解决方案,希望帮大家避坑。</p></blockquote><div class="markdown_views prism-tomorrow-night" id="content_views"><svg style="display: none" xmlns="http://www.w3.org/2000/svg"><path d="M5,0 0,2.5 5,5z" id="raphael-marker-block" stroke-linecap="round" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0)"></path></svg><h2>易语言网络通信编程基础:HTTP/HTTPS/TCP/UDP实战开发</h2><p><img alt="在这里插入图片描述" src="https://i-blog.csdnimg.cn/direct/2833f9e292474461a02718cb94ef7de6.png#pic_center"></p><h3>5.1 引言</h3><p> 在完成了本地数据持久化的学习后,<strong>网络通信编程</strong>是易语言应用开发的又一个核心技能点。现代软件几乎都离不开网络交互:从获取实时天气、新闻资讯的简单API调用,到开发在线聊天工具、文件传输系统的复杂通信,再到爬虫、数据采集的自动化任务,网络通信都是实现这些功能的基础。
</p><p>易语言提供了丰富的网络通信组件和命令,如<strong>internet支持库</strong>用于HTTP/HTTPS通信,<strong>网络通信支持库</strong>用于TCP/UDP通信,<strong>WebSocket支持库</strong>用于实时双向通信。这些组件和命令屏蔽了网络底层的复杂细节,让中文开发者能够快速上手。
</p><h4>5.1.1 学习目标</h4><ul><li>了解<strong>网络通信的基础概念</strong>(IP地址、端口、协议、客户端/服务器模型)</li><li>掌握<strong>HTTP/HTTPS通信</strong>的常用方法(GET/POST请求、响应解析)</li><li>学会使用<strong>TCP通信组件</strong>开发可靠的客户端和服务器端应用</li><li>学会使用<strong>UDP通信组件</strong>开发高效的无连接应用</li><li>综合运用所学知识,完成三个实战案例:
<ul><li>调用天气API获取实时天气</li><li>开发一个简单的TCP聊天工具(服务端+客户端)</li><li>开发一个简单的UDP广播工具</li></ul></li><li>掌握网络通信的<strong>常见问题及解决方案</strong>(网络连接失败、请求超时、数据解析错误等)</li></ul><h4>5.1.2 学习重点</h4><ul><li>HTTP请求的参数构建和响应解析(特别是JSON数据解析)</li><li>TCP通信的连接建立、数据收发和异常处理</li><li>UDP通信的数据包发送和接收</li><li>网络通信的超时设置和重试机制</li><li>天气API的调用和JSON解析库的使用</li><li>TCP聊天工具的UI设计和多客户端通信处理</li></ul><h3>5.2 网络通信基础概念</h3><p>在进行网络通信编程之前,我们需要了解一些基础概念。
</p><h4>5.2.1 IP地址</h4><p>IP地址是设备在网络中的<strong>唯一标识</strong>,类似于家庭住址。常用的IP地址有两种类型:
</p><ul><li><strong>IPv4</strong>:32位二进制数,通常用点分十进制表示(如192.168.1.1)</li><li><strong>IPv6</strong>:128位二进制数,通常用冒分十六进制表示(如2001:0db8:85a3:0000:0000:8a2e:0370:7334)</li></ul><p> 易语言支持IPv4和IPv6地址,但目前IPv4仍占主导地位。
</p><h4>5.2.2 端口</h4><p>端口是设备上<strong>进程的唯一标识</strong>,类似于家庭住址中的房间号。每个网络进程都会占用一个端口,范围是0~65535。其中:
</p><ul><li>0~1023:<strong>系统预留端口</strong>(如HTTP的80端口、HTTPS的443端口、FTP的21端口)</li><li>1024~49151:<strong>注册端口</strong>(由ICANN分配给特定服务)</li><li>49152~65535:<strong>动态端口</strong>(临时分配给客户端进程)</li></ul><h4>5.2.3 网络协议</h4><p>网络协议是设备之间通信的<strong>规则和标准</strong>,常用的网络协议有:
</p><table><thead><tr><th>协议</th><th>类型</th><th>特点</th><th>适用场景</th></tr></thead><tbody><tr><td>TCP</td><td>传输层</td><td>可靠、面向连接、三次握手</td><td>文件传输、聊天工具、邮件发送</td></tr><tr><td>UDP</td><td>传输层</td><td>不可靠、无连接、速度快</td><td>视频通话、音频直播、游戏数据传输</td></tr><tr><td>HTTP</td><td>应用层</td><td>基于TCP的文本协议、无状态</td><td>网页访问、API调用</td></tr><tr><td>HTTPS</td><td>应用层</td><td>基于HTTP的加密协议、安全</td><td>支付、登录等需要安全保障的场景</td></tr></tbody></table><h4>5.2.4 客户端/服务器模型</h4><p>网络通信通常采用<strong>客户端/服务器(C/S)模型</strong>:
</p><ul><li><strong>客户端</strong>:主动发起连接请求的设备(如浏览器、聊天工具客户端)</li><li><strong>服务器</strong>:被动接受连接请求的设备(如Web服务器、聊天工具服务器)</li></ul><h3>5.3 HTTP/HTTPS通信</h3><p>HTTP/HTTPS通信是最常用的网络通信方式,用于获取网页内容和调用API。
</p><h4>5.3.1 internet支持库介绍</h4><p>易语言的<strong>internet支持库</strong>提供了HTTP/HTTPS通信的常用命令和组件,需要在支持库管理器中勾选才能使用。
</p><p>常用命令:
</p><ul><li><code>HTTP读文件()</code>:发送HTTP GET请求,获取响应内容</li><li><code>HTTP访问()</code>:发送HTTP请求(GET/POST/HEAD等),获取响应状态码和内容</li><li><code>HTTP提交()</code>:发送HTTP POST请求,提交表单数据</li><li><code>HTTP下载()</code>:下载文件到本地</li><li><code>HTTP上传()</code>:上传本地文件到服务器</li></ul><h4>5.3.2 HTTP GET请求实战:调用天气API</h4><h5>天气API介绍</h5><p>我们将使用<strong>和风天气API</strong>(https://idqweather.com/)获取实时天气数据。和风天气提供免费的API,每天有600次调用次数限制,适合学习使用。
</p><h5>代码示例</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-e">.版本 2
.支持库 internet
.支持库 spec
.支持库 json ' 需要加载json支持库
' 和风天气API密钥(需要在和风天气官网注册获取)
.程序集变量 g_ApiKey, 文本型, , 静态
' 城市编码(如北京:101010100)
.程序集变量 g_CityCode, 文本型, , 静态
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = “实时天气查询工具”
_启动窗口.宽度 = 600
_启动窗口.高度 = 400
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化API密钥和城市编码
g_ApiKey = “your_api_key_here” ' 替换为你的API密钥
g_CityCode = “101010100” ' 北京的城市编码
' 加载默认天气数据
加载天气数据 ()
.子程序 加载天气数据
.局部变量 请求URL, 文本型
.局部变量 响应内容, 文本型
.局部变量 JSON对象, 类_json
.局部变量 实时天气对象, 类_json
.局部变量 天气描述, 文本型
.局部变量 温度, 文本型
.局部变量 湿度, 文本型
.局部变量 风向, 文本型
.局部变量 风速, 文本型
.局部变量 气压, 文本型
' 构建请求URL
请求URL = “https://devapi.qweather.com/v7/weather/now?location=” + g_CityCode + “&amp;key=” + g_ApiKey
' 发送HTTP GET请求
响应内容 = HTTP读文件 (请求URL)
.如果真 (响应内容 = “”)
    信息框 (“天气数据获取失败!请检查网络连接或API密钥是否正确。”, 0, “错误提示”)
    返回 ()
.如果真结束
' 解析响应内容(JSON格式)
JSON对象.解析 (响应内容)
.如果真 (JSON对象.取通用属性 (“code”, ).文本型 ≠ “200”)
    信息框 (“天气数据获取失败!错误信息:” + JSON对象.取通用属性 (“message”, ).文本型, 0, “错误提示”)
    返回 ()
.如果真结束
' 解析实时天气数据
实时天气对象 = JSON对象.取通用属性 (“now”, )
天气描述 = 实时天气对象.取通用属性 (“text”, ).文本型
温度 = 实时天气对象.取通用属性 (“temp”, ).文本型 + “℃”
湿度 = 实时天气对象.取通用属性 (“humidity”, ).文本型 + “%”
风向 = 实时天气对象.取通用属性 (“windDir”, ).文本型
风速 = 实时天气对象.取通用属性 (“windSpeed”, ).文本型 + “km/h”
气压 = 实时天气对象.取通用属性 (“pressure”, ).文本型 + “hPa”
' 显示天气数据
lblWeather.标题 = “天气:” + 天气描述
lblTemperature.标题 = “温度:” + 温度
lblHumidity.标题 = “湿度:” + 湿度
lblWind.标题 = “风向:” + 风向 + “,风速:” + 风速
lblPressure.标题 = “气压:” + 气压
调试输出 (“天气数据获取成功!响应内容:”, 响应内容)
.子程序 _btnRefresh_被单击
' 刷新天气数据
加载天气数据 ()
.子程序 _cboCity_项目被选择
.局部变量 城市编码数组, 文本型, 数组
.局部变量 选中索引, 整数型
' 城市编码数组(城市名称|城市编码)
城市编码数组 = {“北京|101010100”, “上海|101020100”, “广州|101280101”, “深圳|101280601”, “杭州|101210101”, “南京|101190101”, “成都|101270101”, “武汉|101200101”}
' 获取选中索引
选中索引 = cboCity.现行选中项
' 获取城市编码
g_CityCode = 取文本右边 (城市编码数组 [选中索引], 取文本长度 (城市编码数组 [选中索引]) - 取文本长度 (取文本左边 (城市编码数组 [选中索引], 寻找文本 (城市编码数组 [选中索引], “|”, 1, 真) - 1)) - 1)
' 刷新天气数据
加载天气数据 ()</code></pre>
<h5>调试与运行</h5><ol><li>在和风天气官网注册账号,获取API密钥</li><li>替换代码中的<code>your_api_key_here</code>为你的API密钥</li><li>点击“调试”按钮进入调试模式</li><li>选择不同的城市,查看实时天气数据</li></ol><h4>5.3.3 HTTP POST请求实战:提交表单数据</h4><p>HTTP POST请求通常用于提交表单数据或上传文件,我们将开发一个简单的“用户注册”模拟工具。
</p><h5>代码示例</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-e">.版本 2
.支持库 internet
.支持库 spec
.支持库 json
' 模拟服务器地址
.程序集变量 g_ServerUrl, 文本型, , 静态
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = “用户注册模拟工具”
_启动窗口.宽度 = 500
_启动窗口.高度 = 350
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化模拟服务器地址(可以使用httpbin.org模拟HTTP请求)
g_ServerUrl = “https://httpbin.org/post”
.子程序 _btnRegister_被单击
.局部变量 表单数据, 文本型
.局部变量 响应内容, 文本型
.局部变量 JSON对象, 类_json
.局部变量 请求结果, 文本型
.局部变量 请求时间, 文本型
' 检查输入是否为空
.如果真 (txtUsername.内容 = “” 或 txtPassword.内容 = “” 或 txtEmail.内容 = “”)
    信息框 (“请输入用户名、密码和邮箱!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 构建表单数据(JSON格式)
表单数据 = “{” + #引号 + “username” + #引号 + “:” + #引号 + txtUsername.内容 + #引号 + “,” + #引号 + “password” + #引号 + “:” + #引号 + txtPassword.内容 + #引号 + “,” + #引号 + “email” + #引号 + “:” + #引号 + txtEmail.内容 + #引号 + “}”
' 发送HTTP POST请求
响应内容 = HTTP访问 (g_ServerUrl, “POST”, “Content-Type: application/json” + #换行符 + “”, 到字节集 (表单数据))
.如果真 (响应内容 = “”)
    信息框 (“用户注册失败!请检查网络连接。”, 0, “错误提示”)
    返回 ()
.如果真结束
' 解析响应内容(JSON格式)
JSON对象.解析 (响应内容)
请求结果 = JSON对象.取通用属性 (“status”, ).文本型
.如果真 (请求结果 ≠ “200”)
    信息框 (“用户注册失败!错误信息:” + JSON对象.取通用属性 (“message”, ).文本型, 0, “错误提示”)
    返回 ()
.如果真结束
' 显示请求结果
lblResult.标题 = “注册成功!”
lblResult.字体.颜色 = #绿色
请求时间 = JSON对象.取通用属性 (“json”, ).取通用属性 (“time”, ).文本型
.如果真 (请求时间 = “”)
    请求时间 = 到文本 (取现行时间 (), , “yyyy年MM月dd日 HH时mm分ss秒”)
.如果真结束
调试输出 (“用户注册成功!响应内容:”, 响应内容)</code></pre>
<h5>调试与运行</h5><ol><li>点击“调试”按钮进入调试模式</li><li>输入用户名、密码和邮箱,点击“注册”</li><li>查看响应结果</li></ol><h3>5.4 TCP通信</h3><p>TCP通信是一种<strong>可靠的面向连接的通信方式</strong>,适合开发需要稳定传输的应用,如聊天工具、文件传输系统。
</p><h4>5.4.1 网络通信支持库介绍</h4><p>易语言的<strong>网络通信支持库</strong>提供了TCP和UDP通信的组件,需要在支持库管理器中勾选才能使用。
</p><p>常用组件:
</p><blockquote><p> <strong>优化建议:</strong></p><p>如果你的项目访问量较大,建议增加缓存机制。我们团队在优化后,接口响应时间从800ms降到了50ms,
效果非常明显。具体的缓存策略可以根据业务场景调整。</p></blockquote><p></p><ul><li><strong>客户组件</strong>:用于开发TCP客户端应用</li><li><strong>服务端组件</strong>:用于开发TCP服务器端应用</li><li><strong>UDP组件</strong>:用于开发UDP客户端和服务器端应用</li></ul><h4>5.4.2 TCP聊天工具实战(服务端)</h4><h5>设计思路</h5><ul><li>使用服务端组件监听指定端口</li><li>接受客户端的连接请求</li><li>处理客户端的消息,并转发给其他客户端</li><li>显示客户端的连接和断开信息</li></ul><h5>创建工程与添加组件</h5><ol><li>创建一个新的Windows窗口程序工程</li><li>加载必要的支持库:<strong>系统核心支持库</strong>、<strong>网络通信支持库</strong></li><li>添加以下组件:
<ul><li><strong>标签组件</strong>:2个,分别用于显示“监听端口”和“聊天记录”</li><li><strong>文本框组件</strong>:1个,用于输入监听端口</li><li><strong>编辑框组件</strong>:1个,用于显示聊天记录</li><li><strong>按钮组件</strong>:2个,分别用于“启动监听”和“停止监听”</li><li><strong>服务端组件</strong>:1个,用于监听和接受连接</li></ul></li></ol><h5>设置组件属性</h5><table><thead><tr><th>组件名称</th><th>属性名</th><th>属性值</th></tr></thead><tbody><tr><td>标签1</td><td>标题</td><td>监听端口</td></tr><tr><td>标签1</td><td>名称</td><td>lblPort</td></tr><tr><td>标签2</td><td>标题</td><td>聊天记录</td></tr><tr><td>标签2</td><td>名称</td><td>lblChatRecord</td></tr><tr><td>文本框1</td><td>名称</td><td>txtPort</td></tr><tr><td>文本框1</td><td>内容</td><td>8888</td></tr><tr><td>编辑框1</td><td>名称</td><td>edtChatRecord</td></tr><tr><td>编辑框1</td><td>是否允许多行</td><td>#真</td></tr><tr><td>编辑框1</td><td>滚动条</td><td>#垂直滚动条</td></tr><tr><td>按钮1</td><td>名称</td><td>btnStartListen</td></tr><tr><td>按钮1</td><td>标题</td><td>启动监听</td></tr><tr><td>按钮2</td><td>名称</td><td>btnStopListen</td></tr><tr><td>按钮2</td><td>标题</td><td>停止监听</td></tr><tr><td>按钮2</td><td>禁止</td><td>#真</td></tr><tr><td>服务端组件1</td><td>名称</td><td>sckServer</td></tr></tbody></table><h5>编写代码</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-e">.版本 2
.支持库 spec
.支持库 internet
.支持库 eNetCom
' 已连接的客户端数组
.程序集变量 g_Clients, 文本型, 动态数组
' 聊天记录
.程序集变量 g_ChatRecord, 文本型
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = “TCP聊天工具服务器端”
_启动窗口.宽度 = 600
_启动窗口.高度 = 500
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化聊天记录
g_ChatRecord = “服务器启动时间:” + 到文本 (取现行时间 (), , “yyyy年MM月dd日 HH时mm分ss秒”) + #换行符
.子程序 _btnStartListen_被单击
.局部变量 监听端口, 整数型
' 检查端口是否合法
监听端口 = 到数值 (txtPort.内容)
.如果真 (监听端口 &lt; 1024 或 监听端口 &gt; 65535)
    信息框 (“监听端口必须在1024~65535之间!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 启动监听
.如果真 (sckServer.启动监听 (监听端口) = #假)
    信息框 (“监听端口失败!请检查端口是否被占用。”, 0, “错误提示”)
    返回 ()
.如果真结束
' 禁用启动按钮,启用停止按钮
btnStartListen.禁止 = #真
btnStopListen.禁止 = #假
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “服务器已启动监听,端口:” + 到文本 (监听端口) + #换行符
edtChatRecord.内容 = g_ChatRecord
调试输出 (“服务器已启动监听,端口:”, 监听端口)
.子程序 _btnStopListen_被单击
' 停止监听
sckServer.停止监听 ()
' 禁用停止按钮,启用启动按钮
btnStartListen.禁止 = #假
btnStopListen.禁止 = #真
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “服务器已停止监听!” + #换行符
edtChatRecord.内容 = g_ChatRecord
调试输出 (“服务器已停止监听!”)
.子程序 _sckServer_客户端进入
.局部变量 客户端IP, 文本型
.局部变量 客户端端口, 整数型
' 获取客户端IP和端口
客户端IP = sckServer.取客户端IP (sckServer.现行客户)
客户端端口 = sckServer.取客户端端口 (sckServer.现行客户)
' 添加到已连接客户端数组
加入成员 (g_Clients, 客户端IP + “:” + 到文本 (客户端端口))
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “【系统消息】客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 已连接!” + #换行符
edtChatRecord.内容 = g_ChatRecord
' 向所有已连接客户端广播系统消息
广播系统消息 (“【系统消息】客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 已连接!”)
调试输出 (“客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 已连接!”)
.子程序 _sckServer_客户端离开
.局部变量 客户端IP, 文本型
.局部变量 客户端端口, 整数型
' 获取客户端IP和端口
客户端IP = sckServer.取客户端IP (sckServer.现行客户)
客户端端口 = sckServer.取客户端端口 (sckServer.现行客户)
' 从已连接客户端数组中删除
删除成员 (g_Clients, 查找数组索引 (g_Clients, 客户端IP + “:” + 到文本 (客户端端口)) + 1, 1)
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “【系统消息】客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 已断开!” + #换行符
edtChatRecord.内容 = g_ChatRecord
' 向所有已连接客户端广播系统消息
广播系统消息 (“【系统消息】客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 已断开!”)
调试输出 (“客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 已断开!”)
.子程序 _sckServer_数据到达
.局部变量 客户端IP, 文本型
.局部变量 客户端端口, 整数型
.局部变量 接收数据, 字节集
.局部变量 消息内容, 文本型
' 获取客户端IP和端口
客户端IP = sckServer.取客户端IP (sckServer.现行客户)
客户端端口 = sckServer.取客户端端口 (sckServer.现行客户)
' 接收数据
接收数据 = sckServer.接收数据 (sckServer.现行客户)
消息内容 = 到文本 (接收数据, #UTF_8, )
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “【” + 客户端IP + “:” + 到文本 (客户端端口) + “】” + 消息内容 + #换行符
edtChatRecord.内容 = g_ChatRecord
' 向所有已连接客户端广播消息
广播消息 (“【” + 客户端IP + “:” + 到文本 (客户端端口) + “】” + 消息内容)
调试输出 (“客户端 ” + 客户端IP + “:” + 到文本 (客户端端口) + “ 发送消息:” + 消息内容)
.子程序 查找数组索引, 整数型
.参数 数组, 文本型, 数组
.参数 查找内容, 文本型
.局部变量 i, 整数型
.计次循环首 (取数组成员数 (数组), i)
    .如果真 (数组 = 查找内容)
      返回 (i - 1)
    .如果真结束
.计次循环尾 ()
返回 (-1)
.子程序 广播消息
.参数 消息内容, 文本型
.局部变量 i, 整数型
' 向所有已连接客户端广播消息
.计次循环首 (取数组成员数 (g_Clients), i)
    ' 发送消息
    sckServer.发送数据 (i, 到字节集 (消息内容, #UTF_8, ))
.计次循环尾 ()
.子程序 广播系统消息
.参数 消息内容, 文本型
.局部变量 i, 整数型
' 向所有已连接客户端广播系统消息
.计次循环首 (取数组成员数 (g_Clients), i)
    ' 发送系统消息(使用特殊前缀标识)
    sckServer.发送数据 (i, 到字节集 (“” + 消息内容, #UTF_8, ))
.计次循环尾 ()</code></pre>
<h4>5.4.3 TCP聊天工具实战(客户端)</h4><h5>设计思路</h5><ul><li>使用客户组件连接到服务器端</li><li>发送消息到服务器端</li><li>接收服务器端的消息,并显示在聊天记录中</li><li>处理服务器端的系统消息(使用特殊前缀标识)</li></ul><h5>创建工程与添加组件</h5><ol><li>创建一个新的Windows窗口程序工程</li><li>加载必要的支持库:<strong>系统核心支持库</strong>、<strong>网络通信支持库</strong></li><li>添加以下组件:
<ul><li><strong>标签组件</strong>:3个,分别用于显示“服务器IP”、“服务器端口”和“聊天记录”</li><li><strong>文本框组件</strong>:3个,分别用于输入服务器IP、服务器端口和消息内容</li><li><strong>编辑框组件</strong>:1个,用于显示聊天记录</li><li><strong>按钮组件</strong>:3个,分别用于“连接服务器”、“断开连接”和“发送消息”</li><li><strong>客户组件</strong>:1个,用于连接和通信</li></ul></li></ol><h5>设置组件属性</h5><table><thead><tr><th>组件名称</th><th>属性名</th><th>属性值</th></tr></thead><tbody><tr><td>标签1</td><td>标题</td><td>服务器IP</td></tr><tr><td>标签1</td><td>名称</td><td>lblServerIP</td></tr><tr><td>标签2</td><td>标题</td><td>服务器端口</td></tr><tr><td>标签2</td><td>名称</td><td>lblServerPort</td></tr><tr><td>标签3</td><td>标题</td><td>聊天记录</td></tr><tr><td>标签3</td><td>名称</td><td>lblChatRecord</td></tr><tr><td>文本框1</td><td>名称</td><td>txtServerIP</td></tr><tr><td>文本框1</td><td>内容</td><td>127.0.0.1</td></tr><tr><td>文本框2</td><td>名称</td><td>txtServerPort</td></tr><tr><td>文本框2</td><td>内容</td><td>8888</td></tr><tr><td>文本框3</td><td>名称</td><td>txtMessage</td></tr><tr><td>文本框3</td><td>内容</td><td></td></tr><tr><td>编辑框1</td><td>名称</td><td>edtChatRecord</td></tr><tr><td>编辑框1</td><td>是否允许多行</td><td>#真</td></tr><tr><td>编辑框1</td><td>滚动条</td><td>#垂直滚动条</td></tr><tr><td>按钮1</td><td>名称</td><td>btnConnect</td></tr><tr><td>按钮1</td><td>标题</td><td>连接服务器</td></tr><tr><td>按钮2</td><td>名称</td><td>btnDisconnect</td></tr><tr><td>按钮2</td><td>标题</td><td>断开连接</td></tr><tr><td>按钮2</td><td>禁止</td><td>#真</td></tr><tr><td>按钮3</td><td>名称</td><td>btnSendMessage</td></tr><tr><td>按钮3</td><td>标题</td><td>发送消息</td></tr><tr><td>按钮3</td><td>禁止</td><td>#真</td></tr><tr><td>客户组件1</td><td>名称</td><td>sckClient</td></tr></tbody></table><h5>编写代码</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-e">.版本 2
.支持库 spec
.支持库 internet
.支持库 eNetCom
' 聊天记录
.程序集变量 g_ChatRecord, 文本型
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = “TCP聊天工具客户端”
_启动窗口.宽度 = 550
_启动窗口.高度 = 480
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化聊天记录
g_ChatRecord = “客户端启动时间:” + 到文本 (取现行时间 (), , “yyyy年MM月dd日 HH时mm分ss秒”) + #换行符
.子程序 _btnConnect_被单击
.局部变量 服务器IP, 文本型
.局部变量 服务器端口, 整数型
' 检查服务器IP是否合法
服务器IP = txtServerIP.内容
.如果真 (服务器IP = “”)
    信息框 (“请输入服务器IP!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 检查服务器端口是否合法
服务器端口 = 到数值 (txtServerPort.内容)
.如果真 (服务器端口 &lt; 1024 或 服务器端口 &gt; 65535)
    信息框 (“服务器端口必须在1024~65535之间!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 连接服务器
.如果真 (sckClient.连接 (服务器IP, 服务器端口) = #假)
    信息框 (“连接服务器失败!请检查服务器是否已启动监听,或网络连接是否正常。”, 0, “错误提示”)
    返回 ()
.如果真结束
' 禁用连接按钮,启用断开和发送按钮
btnConnect.禁止 = #真
btnDisconnect.禁止 = #假
btnSendMessage.禁止 = #假
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “【系统消息】已成功连接到服务器!” + #换行符
edtChatRecord.内容 = g_ChatRecord
调试输出 (“已成功连接到服务器!IP:”, 服务器IP, “ 端口:”, 服务器端口)
.子程序 _btnDisconnect_被单击
' 断开连接
sckClient.断开 ()
' 禁用断开和发送按钮,启用连接按钮
btnConnect.禁止 = #假
btnDisconnect.禁止 = #真
btnSendMessage.禁止 = #真
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “【系统消息】已断开与服务器的连接!” + #换行符
edtChatRecord.内容 = g_ChatRecord
调试输出 (“已断开与服务器的连接!”)
.子程序 _btnSendMessage_被单击
.局部变量 消息内容, 文本型
' 检查消息内容是否为空
消息内容 = txtMessage.内容
.如果真 (消息内容 = “”)
    信息框 (“请输入消息内容!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 发送消息
sckClient.发送数据 (到字节集 (消息内容, #UTF_8, ))
' 添加聊天记录
g_ChatRecord = g_ChatRecord + “【我】” + 消息内容 + #换行符
edtChatRecord.内容 = g_ChatRecord
' 清空消息输入框
txtMessage.内容 = “”
调试输出 (“发送消息:” + 消息内容)
.子程序 _sckClient_连接成功
' 连接成功事件(与_ btnConnect_被单击事件一起触发)
调试输出 (“连接成功事件触发!”)
.子程序 _sckClient_连接断开
' 连接断开事件(与_ btnDisconnect_被单击事件一起触发)
调试输出 (“连接断开事件触发!”)
.子程序 _sckClient_数据到达
.局部变量 接收数据, 字节集
.局部变量 消息内容, 文本型
' 接收数据
接收数据 = sckClient.接收数据 ()
消息内容 = 到文本 (接收数据, #UTF_8, )
' 检查是否是系统消息
.如果真 (取文本左边 (消息内容, 8) = “”)
    ' 系统消息,显示黄色文本
    g_ChatRecord = g_ChatRecord + 取文本右边 (消息内容, 取文本长度 (消息内容) - 8) + #换行符
    edtChatRecord.内容 = g_ChatRecord
    edtChatRecord.颜色 = #黄色
.如果真结束
.如果真 (取文本左边 (消息内容, 8) ≠ “”)
    ' 普通消息,显示黑色文本
    g_ChatRecord = g_ChatRecord + 消息内容 + #换行符
    edtChatRecord.内容 = g_ChatRecord
    edtChatRecord.颜色 = #黑色
.如果真结束
调试输出 (“接收消息:” + 消息内容)</code></pre>
<h4>5.4.4 TCP聊天工具调试与运行</h4><ol><li>先运行服务器端程序,点击“启动监听”</li><li>再运行客户端程序,输入服务器IP(127.0.0.1)和端口(8888),点击“连接服务器”</li><li>可以同时运行多个客户端程序,实现群聊功能</li><li>发送消息,查看聊天记录</li><li>断开连接,查看系统消息</li></ol><h3>5.5 UDP通信</h3><p>UDP通信是一种<strong>不可靠的无连接的通信方式</strong>,速度快,适合开发对数据可靠性要求不高但对速度要求高的应用,如视频通话、音频直播、游戏数据传输。
</p><h4>5.5.1 UDP广播工具实战</h4><h5>设计思路</h5><ul><li>使用UDP组件发送广播数据包</li><li>使用UDP组件接收广播数据包</li><li>显示发送和接收的数据包信息</li></ul><h5>创建工程与添加组件</h5><ol><li>创建一个新的Windows窗口程序工程</li><li>加载必要的支持库:<strong>系统核心支持库</strong>、<strong>网络通信支持库</strong></li><li>添加以下组件:
<ul><li><strong>标签组件</strong>:2个,分别用于显示“广播端口”和“数据包信息”</li><li><strong>文本框组件</strong>:2个,分别用于输入广播端口和数据包内容</li><li><strong>编辑框组件</strong>:1个,用于显示数据包信息</li><li><strong>按钮组件</strong>:2个,分别用于“发送广播”和“接收广播”</li><li><strong>UDP组件</strong>:1个,用于发送和接收数据包</li></ul></li></ol><h5>设置组件属性</h5><table><thead><tr><th>组件名称</th><th>属性名</th><th>属性值</th></tr></thead><tbody><tr><td>标签1</td><td>标题</td><td>广播端口</td></tr><tr><td>标签1</td><td>名称</td><td>lblPort</td></tr><tr><td>标签2</td><td>标题</td><td>数据包内容</td></tr><tr><td>标签2</td><td>名称</td><td>lblPacketContent</td></tr><tr><td>标签3</td><td>标题</td><td>数据包信息</td></tr><tr><td>标签3</td><td>名称</td><td>lblPacketInfo</td></tr><tr><td>文本框1</td><td>名称</td><td>txtPort</td></tr><tr><td>文本框1</td><td>内容</td><td>9999</td></tr><tr><td>文本框2</td><td>名称</td><td>txtContent</td></tr><tr><td>文本框2</td><td>内容</td><td>这是一个UDP广播数据包!</td></tr><tr><td>编辑框1</td><td>名称</td><td>edtPacketInfo</td></tr><tr><td>编辑框1</td><td>是否允许多行</td><td>#真</td></tr><tr><td>编辑框1</td><td>滚动条</td><td>#垂直滚动条</td></tr><tr><td>按钮1</td><td>名称</td><td>btnSendBroadcast</td></tr><tr><td>按钮1</td><td>标题</td><td>发送广播</td></tr><tr><td>按钮2</td><td>名称</td><td>btnReceiveBroadcast</td></tr><tr><td>按钮2</td><td>标题</td><td>接收广播</td></tr><tr><td>按钮2</td><td>禁止</td><td>#真</td></tr><tr><td>UDP组件1</td><td>名称</td><td>udpBroadcast</td></tr></tbody></table><h5>编写代码</h5>
<pre style="white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important"><code class="prism language-e">.版本 2
.支持库 spec
.支持库 internet
.支持库 eNetCom
' 数据包信息
.程序集变量 g_PacketInfo, 文本型
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = “UDP广播工具”
_启动窗口.宽度 = 550
_启动窗口.高度 = 450
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化数据包信息
g_PacketInfo = “工具启动时间:” + 到文本 (取现行时间 (), , “yyyy年MM月dd日 HH时mm分ss秒”) + #换行符
.子程序 _btnSendBroadcast_被单击
.局部变量 广播端口, 整数型
.局部变量 数据包内容, 文本型
' 检查广播端口是否合法
广播端口 = 到数值 (txtPort.内容)
.如果真 (广播端口 &lt; 1024 或 广播端口 &gt; 65535)
    信息框 (“广播端口必须在1024~65535之间!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 检查数据包内容是否为空
数据包内容 = txtContent.内容
.如果真 (数据包内容 = “”)
    信息框 (“请输入数据包内容!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 发送广播数据包(广播地址为255.255.255.255)
udpBroadcast.发送数据 (“255.255.255.255”, 广播端口, 到字节集 (数据包内容, #UTF_8, ))
' 添加数据包信息
g_PacketInfo = g_PacketInfo + “【发送数据包】时间:” + 到文本 (取现行时间 (), , “HH时mm分ss秒”) + “ 目标地址:255.255.255.255:” + 到文本 (广播端口) + “ 内容:” + 数据包内容 + #换行符
edtPacketInfo.内容 = g_PacketInfo
调试输出 (“发送广播数据包!目标地址:255.255.255.255:” + 到文本 (广播端口) + “ 内容:” + 数据包内容)
.子程序 _btnReceiveBroadcast_被单击
.局部变量 监听端口, 整数型
' 检查监听端口是否合法
监听端口 = 到数值 (txtPort.内容)
.如果真 (监听端口 &lt; 1024 或 监听端口 &gt; 65535)
    信息框 (“监听端口必须在1024~65535之间!”, 0, “错误提示”)
    返回 ()
.如果真结束
' 绑定监听端口
.如果真 (udpBroadcast.绑定端口 (监听端口) = #假)
    信息框 (“绑定监听端口失败!请检查端口是否被占用。”, 0, “错误提示”)
    返回 ()
.如果真结束
' 禁用发送按钮,启用接收按钮
btnSendBroadcast.禁止 = #真
btnReceiveBroadcast.禁止 = #真
' 添加数据包信息
g_PacketInfo = g_PacketInfo + “【系统消息】已开始监听广播,端口:” + 到文本 (监听端口) + “,等待接收数据包... ” + #换行符
edtPacketInfo.内容 = g_PacketInfo
调试输出 (“已开始监听广播,端口:”, 监听端口)
.子程序 _udpBroadcast_数据到达
.局部变量 发送方IP, 文本型
.局部变量 发送方端口, 整数型
.局部变量 接收数据, 字节集
.局部变量 数据包内容, 文本型
' 获取发送方IP和端口
发送方IP = udpBroadcast.取发送方IP ()
发送方端口 = udpBroadcast.取发送方端口 ()
' 接收数据
接收数据 = udpBroadcast.接收数据 ()
数据包内容 = 到文本 (接收数据, #UTF_8, )
' 添加数据包信息
g_PacketInfo = g_PacketInfo + “【接收数据包】时间:” + 到文本 (取现行时间 (), , “HH时mm分ss秒”) + “ 发送方地址:” + 发送方IP + “:” + 到文本 (发送方端口) + “ 内容:” + 数据包内容 + #换行符
edtPacketInfo.内容 = g_PacketInfo
调试输出 (“接收数据包!发送方地址:” + 发送方IP + “:” + 到文本 (发送方端口) + “ 内容:” + 数据包内容)</code></pre>
<h4>5.5.2 UDP广播工具调试与运行</h4><ol><li>运行两个或更多的UDP广播工具实例</li><li>在每个实例中输入相同的广播端口(如9999)</li><li>在一个实例中点击“发送广播”,其他实例会接收到广播数据包</li><li>在一个实例中点击“接收广播”,可以持续接收广播数据包</li></ol><h3>5.6 网络通信常见问题与解决方案</h3><h4>5.6.1 网络连接失败</h4><p><strong>问题现象</strong>:程序无法连接到服务器,提示“连接服务器失败”或“端口绑定失败”。
</p><p><strong>原因</strong>:
</p><ul><li>服务器未启动监听</li><li>服务器IP或端口输入错误</li><li>网络连接不稳定</li><li>防火墙拦截了网络通信</li><li>端口被其他程序占用</li></ul><p><strong>解决方案</strong>:
</p><ul><li>确保服务器已启动监听</li><li>检查服务器IP和端口输入是否正确</li><li>检查网络连接是否稳定</li><li>关闭防火墙或添加防火墙例外</li><li>更换未被占用的端口</li></ul><h4>5.6.2 请求超时</h4><p><strong>问题现象</strong>:HTTP请求或TCP连接超时,提示“请求超时”或“连接超时”。
</p><p><strong>原因</strong>:
</p><ul><li>服务器响应慢</li><li>网络延迟高</li><li>防火墙拦截了响应数据包</li><li>请求参数不正确</li></ul><p><strong>解决方案</strong>:
</p><ul><li>优化服务器响应速度</li><li>检查网络延迟是否过高</li><li>关闭防火墙或添加防火墙例外</li><li>检查请求参数是否正确</li><li>添加超时设置和重试机制</li></ul><h4>5.6.3 数据解析错误</h4><p><strong>问题现象</strong>:HTTP响应数据解析错误,提示“JSON解析失败”或“HTML解析失败”。
</p><p><strong>原因</strong>:
</p><ul><li>响应数据格式不正确</li><li>请求参数不正确</li><li>服务器返回了错误信息</li><li>编码方式不匹配</li></ul><p><strong>解决方案</strong>:
</p><ul><li>检查响应数据格式是否正确</li><li>检查请求参数是否正确</li><li>处理服务器返回的错误信息</li><li>确保编码方式匹配(如UTF-8、ANSI、Unicode)</li></ul><h4>5.6.4 防火墙拦截</h4><p><strong>问题现象</strong>:程序无法发送或接收网络数据,提示“网络连接失败”或“数据到达事件未触发”。
</p><p><strong>原因</strong>:
</p><ul><li>防火墙拦截了程序的网络通信</li><li>程序没有网络通信权限</li></ul><p><strong>解决方案</strong>:
</p><ul><li>关闭防火墙</li><li>添加防火墙例外(允许程序发送和接收网络数据)</li><li>以管理员身份运行程序</li></ul><h3>5.7 总结</h3><p>✅ 本章详细介绍了易语言网络通信编程的基础概念和常用方法,包括<strong>HTTP/HTTPS通信</strong>、<strong>TCP通信</strong>和<strong>UDP通信</strong>。通过学习,我们掌握了:
</p><ul><li>网络通信的基础概念(IP地址、端口、协议、客户端/服务器模型)</li><li>HTTP/HTTPS通信的常用方法(GET/POST请求、响应解析)</li><li>TCP通信组件的使用(客户组件、服务端组件)</li><li>UDP通信组件的使用(UDP组件)</li><li>综合运用所学知识,完成了三个实战案例:
<ul><li>调用天气API获取实时天气</li><li>开发一个简单的TCP聊天工具(服务端+客户端)</li><li>开发一个简单的UDP广播工具</li></ul></li><li>掌握了网络通信的常见问题及解决方案</li></ul><p>网络通信编程是现代软件开发的重要环节,易语言提供了丰富的网络通信组件和命令,让中文开发者能够快速上手。在实际开发中,还可以使用WebSocket支持库开发实时双向通信应用,或使用爬虫支持库开发数据采集应用。
</p><p>希望大家能够认真学习本章内容,多动手实践,理解网络通信的核心原理,为后续学习高级功能(如数据库远程连接、云服务对接)打下坚实的基础。
</p></div><br><br>
来源:https://www.cnblogs.com/yangykaifa/p/19622428
頁: [1]
查看完整版本: 生产环境易语言网络通信编程基础:HTTP/HTTPS/TCP/UDP实战开发最佳实践与性能优化