易语言网络通信编程基础:HTTP/HTTPS/TCP/UDP实战开发

5.1 引言
💡 在完成了本地数据持久化的学习后,网络通信编程是易语言应用开发的又一个核心技能点。现代软件几乎都离不开网络交互:从获取实时天气、新闻资讯的简单API调用,到开发在线聊天工具、文件传输系统的复杂通信,再到爬虫、数据采集的自动化任务,网络通信都是实现这些功能的基础。
易语言提供了丰富的网络通信组件和命令,如internet支持库 用于HTTP/HTTPS通信,网络通信支持库 用于TCP/UDP通信,WebSocket支持库用于实时双向通信。这些组件和命令屏蔽了网络底层的复杂细节,让中文开发者能够快速上手。
5.1.1 学习目标
- 了解网络通信的基础概念(IP地址、端口、协议、客户端/服务器模型)
- 掌握HTTP/HTTPS通信的常用方法(GET/POST请求、响应解析)
- 学会使用TCP通信组件开发可靠的客户端和服务器端应用
- 学会使用UDP通信组件开发高效的无连接应用
- 综合运用所学知识,完成三个实战案例:
- 调用天气API获取实时天气
- 开发一个简单的TCP聊天工具(服务端+客户端)
- 开发一个简单的UDP广播工具
- 掌握网络通信的常见问题及解决方案(网络连接失败、请求超时、数据解析错误等)
5.1.2 学习重点
- HTTP请求的参数构建和响应解析(特别是JSON数据解析)
- TCP通信的连接建立、数据收发和异常处理
- UDP通信的数据包发送和接收
- 网络通信的超时设置和重试机制
- 天气API的调用和JSON解析库的使用
- TCP聊天工具的UI设计和多客户端通信处理
5.2 网络通信基础概念
在进行网络通信编程之前,我们需要了解一些基础概念。
5.2.1 IP地址
IP地址是设备在网络中的唯一标识,类似于家庭住址。常用的IP地址有两种类型:
- IPv4:32位二进制数,通常用点分十进制表示(如192.168.1.1)
- IPv6:128位二进制数,通常用冒分十六进制表示(如2001:0db8:85a3:0000:0000:8a2e:0370:7334)
💡 易语言支持IPv4和IPv6地址,但目前IPv4仍占主导地位。
5.2.2 端口
端口是设备上进程的唯一标识,类似于家庭住址中的房间号。每个网络进程都会占用一个端口,范围是0~65535。其中:
- 0~1023:系统预留端口(如HTTP的80端口、HTTPS的443端口、FTP的21端口)
- 1024~49151:注册端口(由ICANN分配给特定服务)
- 49152~65535:动态端口(临时分配给客户端进程)
5.2.3 网络协议
网络协议是设备之间通信的规则和标准,常用的网络协议有:
| 协议 | 类型 | 特点 | 适用场景 |
|---|---|---|---|
| TCP | 传输层 | 可靠、面向连接、三次握手 | 文件传输、聊天工具、邮件发送 |
| UDP | 传输层 | 不可靠、无连接、速度快 | 视频通话、音频直播、游戏数据传输 |
| HTTP | 应用层 | 基于TCP的文本协议、无状态 | 网页访问、API调用 |
| HTTPS | 应用层 | 基于HTTP的加密协议、安全 | 支付、登录等需要安全保障的场景 |
5.2.4 客户端/服务器模型
网络通信通常采用客户端/服务器(C/S)模型:
- 客户端:主动发起连接请求的设备(如浏览器、聊天工具客户端)
- 服务器:被动接受连接请求的设备(如Web服务器、聊天工具服务器)
5.3 HTTP/HTTPS通信
HTTP/HTTPS通信是最常用的网络通信方式,用于获取网页内容和调用API。
5.3.1 internet支持库介绍
易语言的internet支持库提供了HTTP/HTTPS通信的常用命令和组件,需要在支持库管理器中勾选才能使用。
常用命令:
HTTP读文件():发送HTTP GET请求,获取响应内容HTTP访问():发送HTTP请求(GET/POST/HEAD等),获取响应状态码和内容HTTP提交():发送HTTP POST请求,提交表单数据HTTP下载():下载文件到本地HTTP上传():上传本地文件到服务器
5.3.2 HTTP GET请求实战:调用天气API
天气API介绍
我们将使用和风天气API(https://idqweather.com/)获取实时天气数据。和风天气提供免费的API,每天有600次调用次数限制,适合学习使用。
代码示例
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 + "&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)
' 刷新天气数据
加载天气数据 ()
调试与运行
- 在和风天气官网注册账号,获取API密钥
- 替换代码中的
your_api_key_here为你的API密钥 - 点击"调试"按钮进入调试模式
- 选择不同的城市,查看实时天气数据
5.3.3 HTTP POST请求实战:提交表单数据
HTTP POST请求通常用于提交表单数据或上传文件,我们将开发一个简单的"用户注册"模拟工具。
代码示例
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秒")
.如果真结束
调试输出 ("用户注册成功!响应内容:", 响应内容)
调试与运行
- 点击"调试"按钮进入调试模式
- 输入用户名、密码和邮箱,点击"注册"
- 查看响应结果
5.4 TCP通信
TCP通信是一种可靠的面向连接的通信方式,适合开发需要稳定传输的应用,如聊天工具、文件传输系统。
5.4.1 网络通信支持库介绍
易语言的网络通信支持库提供了TCP和UDP通信的组件,需要在支持库管理器中勾选才能使用。
常用组件:
- 客户组件:用于开发TCP客户端应用
- 服务端组件:用于开发TCP服务器端应用
- UDP组件:用于开发UDP客户端和服务器端应用
5.4.2 TCP聊天工具实战(服务端)
设计思路
- 使用服务端组件监听指定端口
- 接受客户端的连接请求
- 处理客户端的消息,并转发给其他客户端
- 显示客户端的连接和断开信息
创建工程与添加组件
- 创建一个新的Windows窗口程序工程
- 加载必要的支持库:系统核心支持库 、网络通信支持库
- 添加以下组件:
- 标签组件:2个,分别用于显示"监听端口"和"聊天记录"
- 文本框组件:1个,用于输入监听端口
- 编辑框组件:1个,用于显示聊天记录
- 按钮组件:2个,分别用于"启动监听"和"停止监听"
- 服务端组件:1个,用于监听和接受连接
设置组件属性
| 组件名称 | 属性名 | 属性值 |
|---|---|---|
| 标签1 | 标题 | 监听端口 |
| 标签1 | 名称 | lblPort |
| 标签2 | 标题 | 聊天记录 |
| 标签2 | 名称 | lblChatRecord |
| 文本框1 | 名称 | txtPort |
| 文本框1 | 内容 | 8888 |
| 编辑框1 | 名称 | edtChatRecord |
| 编辑框1 | 是否允许多行 | #真 |
| 编辑框1 | 滚动条 | #垂直滚动条 |
| 按钮1 | 名称 | btnStartListen |
| 按钮1 | 标题 | 启动监听 |
| 按钮2 | 名称 | btnStopListen |
| 按钮2 | 标题 | 停止监听 |
| 按钮2 | 禁止 | #真 |
| 服务端组件1 | 名称 | sckServer |
编写代码
e
.版本 2
.支持库 spec
.支持库 internet
.支持库 eNetCom
' 已连接的客户端数组
.程序集变量 g_Clients, 文本型, 动态数组
' 聊天记录
.程序集变量 g_ChatRecord, 文本型
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = "TCP聊天工具服务器端"
_启动窗口.宽度 = 600
_启动窗口.高度 = 500
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化聊天记录
g_ChatRecord = "服务器启动时间:" + 到文本 (取现行时间 (), , "yyyy年MM月dd日 HH时mm分ss秒") + #换行符
.子程序 _btnStartListen_被单击
.局部变量 监听端口, 整数型
' 检查端口是否合法
监听端口 = 到数值 (txtPort.内容)
.如果真 (监听端口 < 1024 或 监听端口 > 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] = 查找内容)
返回 (i - 1)
.如果真结束
.计次循环尾 ()
返回 (-1)
.子程序 广播消息
.参数 消息内容, 文本型
.局部变量 i, 整数型
' 向所有已连接客户端广播消息
.计次循环首 (取数组成员数 (g_Clients), i)
' 发送消息
sckServer.发送数据 (i, 到字节集 (消息内容, #UTF_8, ))
.计次循环尾 ()
.子程序 广播系统消息
.参数 消息内容, 文本型
.局部变量 i, 整数型
' 向所有已连接客户端广播系统消息
.计次循环首 (取数组成员数 (g_Clients), i)
' 发送系统消息(使用特殊前缀标识)
sckServer.发送数据 (i, 到字节集 ("[SYSTEM]" + 消息内容, #UTF_8, ))
.计次循环尾 ()
5.4.3 TCP聊天工具实战(客户端)
设计思路
- 使用客户组件连接到服务器端
- 发送消息到服务器端
- 接收服务器端的消息,并显示在聊天记录中
- 处理服务器端的系统消息(使用特殊前缀标识)
创建工程与添加组件
- 创建一个新的Windows窗口程序工程
- 加载必要的支持库:系统核心支持库 、网络通信支持库
- 添加以下组件:
- 标签组件:3个,分别用于显示"服务器IP"、"服务器端口"和"聊天记录"
- 文本框组件:3个,分别用于输入服务器IP、服务器端口和消息内容
- 编辑框组件:1个,用于显示聊天记录
- 按钮组件:3个,分别用于"连接服务器"、"断开连接"和"发送消息"
- 客户组件:1个,用于连接和通信
设置组件属性
| 组件名称 | 属性名 | 属性值 |
|---|---|---|
| 标签1 | 标题 | 服务器IP |
| 标签1 | 名称 | lblServerIP |
| 标签2 | 标题 | 服务器端口 |
| 标签2 | 名称 | lblServerPort |
| 标签3 | 标题 | 聊天记录 |
| 标签3 | 名称 | lblChatRecord |
| 文本框1 | 名称 | txtServerIP |
| 文本框1 | 内容 | 127.0.0.1 |
| 文本框2 | 名称 | txtServerPort |
| 文本框2 | 内容 | 8888 |
| 文本框3 | 名称 | txtMessage |
| 文本框3 | 内容 | |
| 编辑框1 | 名称 | edtChatRecord |
| 编辑框1 | 是否允许多行 | #真 |
| 编辑框1 | 滚动条 | #垂直滚动条 |
| 按钮1 | 名称 | btnConnect |
| 按钮1 | 标题 | 连接服务器 |
| 按钮2 | 名称 | btnDisconnect |
| 按钮2 | 标题 | 断开连接 |
| 按钮2 | 禁止 | #真 |
| 按钮3 | 名称 | btnSendMessage |
| 按钮3 | 标题 | 发送消息 |
| 按钮3 | 禁止 | #真 |
| 客户组件1 | 名称 | sckClient |
编写代码
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.内容)
.如果真 (服务器端口 < 1024 或 服务器端口 > 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) = "[SYSTEM]")
' 系统消息,显示黄色文本
g_ChatRecord = g_ChatRecord + 取文本右边 (消息内容, 取文本长度 (消息内容) - 8) + #换行符
edtChatRecord.内容 = g_ChatRecord
edtChatRecord.颜色 = #黄色
.如果真结束
.如果真 (取文本左边 (消息内容, 8) ≠ "[SYSTEM]")
' 普通消息,显示黑色文本
g_ChatRecord = g_ChatRecord + 消息内容 + #换行符
edtChatRecord.内容 = g_ChatRecord
edtChatRecord.颜色 = #黑色
.如果真结束
调试输出 ("接收消息:" + 消息内容)
5.4.4 TCP聊天工具调试与运行
- 先运行服务器端程序,点击"启动监听"
- 再运行客户端程序,输入服务器IP(127.0.0.1)和端口(8888),点击"连接服务器"
- 可以同时运行多个客户端程序,实现群聊功能
- 发送消息,查看聊天记录
- 断开连接,查看系统消息
5.5 UDP通信
UDP通信是一种不可靠的无连接的通信方式,速度快,适合开发对数据可靠性要求不高但对速度要求高的应用,如视频通话、音频直播、游戏数据传输。
5.5.1 UDP广播工具实战
设计思路
- 使用UDP组件发送广播数据包
- 使用UDP组件接收广播数据包
- 显示发送和接收的数据包信息
创建工程与添加组件
- 创建一个新的Windows窗口程序工程
- 加载必要的支持库:系统核心支持库 、网络通信支持库
- 添加以下组件:
- 标签组件:2个,分别用于显示"广播端口"和"数据包信息"
- 文本框组件:2个,分别用于输入广播端口和数据包内容
- 编辑框组件:1个,用于显示数据包信息
- 按钮组件:2个,分别用于"发送广播"和"接收广播"
- UDP组件:1个,用于发送和接收数据包
设置组件属性
| 组件名称 | 属性名 | 属性值 |
|---|---|---|
| 标签1 | 标题 | 广播端口 |
| 标签1 | 名称 | lblPort |
| 标签2 | 标题 | 数据包内容 |
| 标签2 | 名称 | lblPacketContent |
| 标签3 | 标题 | 数据包信息 |
| 标签3 | 名称 | lblPacketInfo |
| 文本框1 | 名称 | txtPort |
| 文本框1 | 内容 | 9999 |
| 文本框2 | 名称 | txtContent |
| 文本框2 | 内容 | 这是一个UDP广播数据包! |
| 编辑框1 | 名称 | edtPacketInfo |
| 编辑框1 | 是否允许多行 | #真 |
| 编辑框1 | 滚动条 | #垂直滚动条 |
| 按钮1 | 名称 | btnSendBroadcast |
| 按钮1 | 标题 | 发送广播 |
| 按钮2 | 名称 | btnReceiveBroadcast |
| 按钮2 | 标题 | 接收广播 |
| 按钮2 | 禁止 | #真 |
| UDP组件1 | 名称 | udpBroadcast |
编写代码
e
.版本 2
.支持库 spec
.支持库 internet
.支持库 eNetCom
' 数据包信息
.程序集变量 g_PacketInfo, 文本型
.子程序 __启动窗口_创建完毕
' 初始化组件属性
_启动窗口.标题 = "UDP广播工具"
_启动窗口.宽度 = 550
_启动窗口.高度 = 450
_启动窗口.左边 = (取屏幕宽度 () - _启动窗口.宽度) ÷ 2
_启动窗口.顶边 = (取屏幕高度 () - _启动窗口.高度) ÷ 2
' 初始化数据包信息
g_PacketInfo = "工具启动时间:" + 到文本 (取现行时间 (), , "yyyy年MM月dd日 HH时mm分ss秒") + #换行符
.子程序 _btnSendBroadcast_被单击
.局部变量 广播端口, 整数型
.局部变量 数据包内容, 文本型
' 检查广播端口是否合法
广播端口 = 到数值 (txtPort.内容)
.如果真 (广播端口 < 1024 或 广播端口 > 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.内容)
.如果真 (监听端口 < 1024 或 监听端口 > 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 + ":" + 到文本 (发送方端口) + " 内容:" + 数据包内容)
5.5.2 UDP广播工具调试与运行
- 运行两个或更多的UDP广播工具实例
- 在每个实例中输入相同的广播端口(如9999)
- 在一个实例中点击"发送广播",其他实例会接收到广播数据包
- 在一个实例中点击"接收广播",可以持续接收广播数据包
5.6 网络通信常见问题与解决方案
5.6.1 网络连接失败
问题现象:程序无法连接到服务器,提示"连接服务器失败"或"端口绑定失败"。
原因:
- 服务器未启动监听
- 服务器IP或端口输入错误
- 网络连接不稳定
- 防火墙拦截了网络通信
- 端口被其他程序占用
解决方案:
- 确保服务器已启动监听
- 检查服务器IP和端口输入是否正确
- 检查网络连接是否稳定
- 关闭防火墙或添加防火墙例外
- 更换未被占用的端口
5.6.2 请求超时
问题现象:HTTP请求或TCP连接超时,提示"请求超时"或"连接超时"。
原因:
- 服务器响应慢
- 网络延迟高
- 防火墙拦截了响应数据包
- 请求参数不正确
解决方案:
- 优化服务器响应速度
- 检查网络延迟是否过高
- 关闭防火墙或添加防火墙例外
- 检查请求参数是否正确
- 添加超时设置和重试机制
5.6.3 数据解析错误
问题现象:HTTP响应数据解析错误,提示"JSON解析失败"或"HTML解析失败"。
原因:
- 响应数据格式不正确
- 请求参数不正确
- 服务器返回了错误信息
- 编码方式不匹配
解决方案:
- 检查响应数据格式是否正确
- 检查请求参数是否正确
- 处理服务器返回的错误信息
- 确保编码方式匹配(如UTF-8、ANSI、Unicode)
5.6.4 防火墙拦截
问题现象:程序无法发送或接收网络数据,提示"网络连接失败"或"数据到达事件未触发"。
原因:
- 防火墙拦截了程序的网络通信
- 程序没有网络通信权限
解决方案:
- 关闭防火墙
- 添加防火墙例外(允许程序发送和接收网络数据)
- 以管理员身份运行程序
5.7 总结
✅ 本章详细介绍了易语言网络通信编程的基础概念和常用方法,包括HTTP/HTTPS通信 、TCP通信 和UDP通信。通过学习,我们掌握了:
- 网络通信的基础概念(IP地址、端口、协议、客户端/服务器模型)
- HTTP/HTTPS通信的常用方法(GET/POST请求、响应解析)
- TCP通信组件的使用(客户组件、服务端组件)
- UDP通信组件的使用(UDP组件)
- 综合运用所学知识,完成了三个实战案例:
- 调用天气API获取实时天气
- 开发一个简单的TCP聊天工具(服务端+客户端)
- 开发一个简单的UDP广播工具
- 掌握了网络通信的常见问题及解决方案
网络通信编程是现代软件开发的重要环节,易语言提供了丰富的网络通信组件和命令,让中文开发者能够快速上手。在实际开发中,还可以使用WebSocket支持库开发实时双向通信应用,或使用爬虫支持库开发数据采集应用。
希望大家能够认真学习本章内容,多动手实践,理解网络通信的核心原理,为后续学习高级功能(如数据库远程连接、云服务对接)打下坚实的基础。