新闻详情

新闻详情

首页 / 资讯中心 / 详情

17 嵌入式操作系统 | uloop 事件循环:TCP 客户端

发布时间:2026/9/28 20:35:34来源:尧图网络
17 嵌入式操作系统 | uloop 事件循环:TCP 客户端
嵌入式操作系统 | uloop 事件循环TCP 客户端本课程开源地址Giteehttps://gitee.com/fujianxinxi/qianrushixitongyingyongkaifa.git课件、示例代码与验收脚本都在该仓库可直接git clone或下载 ZIP 使用。模块五 · 2 学时 · 环境VMware Ubuntu 20.04一句话概述把 uloop 用到 TCP 上先 connect 连上服务器再把已连接的套接字交给 uloop 监视定时往服务器发消息并打印回复重点是看懂 recv 返回 0服务器关闭连接这个现象一步一步给出命令与运行结果配套课堂练习与课后作业。本节目标能说清 uloop 版 TCP 客户端与 UDP 版写法的区别要先 connect之后只用这一个 fd会写连接 交给 uloop 监视 定时发送的 TCP 客户端能看懂服务器关闭连接时recv返回 0 的现象并知道该怎么处理一、讲解内容1.1 知识讲解TCP 比 UDP 多一步 connect。UDP 谁都能发TCP 必须先connect()连上服务器三次握手成功后拿到一个已连接的套接字之后所有收发都用它再也不用写对方地址。连接也要交给 uloop。连上以后把这个 fd 挂给 uloopuloop_fd_add(ufd, ULOOP_READ)服务器发数据过来时uloop 就调用我们的回调去recv。recv的返回值一定要会看本课重点现象返回值含义该怎么办 0收到了这么多字节打印/处理数据0对方关闭了连接不是出错关掉 fd、结束循环或重连 0出错perror打印后处理定时发送用 uloop 定时器。本课让客户端每 3 秒发一条消息用的是uloop_timeout_set(tick, 3000)。定时器的细节下节课讲这里先会用。为什么不自己写 while 循环。如果写成while (1) { sleep(3); send(); recv(); }睡眠期间服务器发来的数据要等醒来才能处理交给 uloop收发和定时各走各的回调互不耽误——这就是事件驱动的写法。1.2 操作步骤一条命令一步每步都有现象第 1 步编译cd~/lab/课时17-uloop的TCP客户端 gcc-Wall-Wextra-ouloop_tcp uloop_tcp.c-lubox现象无输出即成功。编译要链接 libubox-lubox因为 uloop 在 libubox 里。第 2 步先启动 Python 回显服务器终端 A必须先开python3 tcp_echo_server.py9999现象TCP 回显服务器已启动监听 9999 端口CtrlC 退出第 3 步终端 B 运行 C 客户端后开./uloop_tcp127.0.0.19999现象等 3 秒开始发第一条每 3 秒一条本机实测① uloop 初始化完成 ② 已连接到 127.0.0.1:9999 ③ 连接已交给 uloop 监视 ④ 进入 uloop_run()每 3 秒发一条收到回复就打印按 CtrlC 退出 → 已发送15 字节第 1 条消息 ← 收到服务器回复20 字节ECHO:第 1 条消息 → 已发送15 字节第 2 条消息 ← 收到服务器回复20 字节ECHO:第 2 条消息终端 APython 服务器对应的现象客户端 127.0.0.1:40080 已连接 收到: 第 1 条消息 收到: 第 2 条消息第 4 步把服务器关掉看客户端反应重点现象在终端 A 按CtrlC停掉 Python 服务器回到终端 B 观察✗ 服务器关闭了连接recv 返回 0客户端退出 ⑤ uloop 结束客户端退出这就是recv返回 0 的现场对方关闭连接属于正常事件不是错误程序应当把它当成该收摊了真实项目里通常是重连。第 5 步收工 顺序口诀。服务先开、客户端后开、服务最后关。1.3 常见错误与排查现象原因解决connect服务器没开...: Connection refused服务器没启动或端口写错先确认终端 A 打印了已启动核对端口Connection timed outIP 不通不同网段/防火墙先ping 对端IP连上了但一直没消息定时器还没到 3 秒等 3 秒本课就是 3 秒一条客户端不发数据忘记设置tick.cb或没uloop_timeout_set检查第 ④ 步那两行代码服务器关了客户端没反应回调里没判断n 0按 1.1 的返回值表处理想一直重连却没实现本课只做断开就退出见作业选做题用uloop_timeout_set3 秒后重新 connect二、学生练习本节命令速查表命令作用示例gcc … -lubox编译 uloop 程序gcc -Wall -Wextra -o uloop_tcp uloop_tcp.c -luboxpython3 tcp_echo_server.py 端口启动 Python 回显服务先开python3 tcp_echo_server.py 9999./uloop_tcp IP 端口运行 C 客户端./uloop_tcp 127.0.0.1 9999ss -tnp | grep 端口看 TCP 连接状态ESTABss -tnp | grep 9999CtrlC服务器端停服务器观察客户端 recv 0 现象—编号任务提示预期结果L17.1按步骤跑通一次先服务器后客户端客户端每 3 秒发一条并收到 ECHOL17.2观察 recv 返回 0服务器端 CtrlC客户端打印服务器关闭了连接recv 返回 0并退出L17.3用ss看连接客户端运行时执行能看到 ESTAB 状态的连接L17.4改发送周期为 1 秒把两处3000改成1000每秒一条L17.5连同学的虚拟机IP 换成同学 IP两边端口一致同学的服务器打印你发的消息L17.6服务器没开就运行直接运行客户端报Connection refused三、作业必做完成 L17.1、L17.2提交两个终端截图客户端 服务端与recv 返回 0的现象截图并回答① TCP 客户端为什么要先connect②recv返回 0 是什么意思程序应该怎么处理③ 为什么要把 fd 交给 uloop而不是自己写 while 循环选做让客户端在断开后自动重连在recv返回 0 的分支里用uloop_timeout_set(retry, 3000)3 秒后重新connect提示把连接代码抽成一个函数反复调用提交截图 文字回答命名课时17-作业截图.png四、本节小结与下节预告本节把 uloop 用到 TCP 上connect 一次 → 交给 uloop 监视 → 定时发送 回调收数据并第一次看到recv返回 0 这个对方关闭的现场。下节专门讲 uloop 定时器周期任务怎么做、和一次性任务有什么区别并把定时采集 网络上报跑起来。附录怎么运行 完整代码一个课件就够用先按附录 A 的顺序敲命令服务端/对端先开自己的程序后开再按附录 B 抄代码。行尾请用 LF。附录 A怎么运行注意先后顺序gcc-Wall-Wextra-ouloop_tcp uloop_tcp.c-luboxpython3 tcp_echo_server.py9999# 终端A先启动回显服务./uloop_tcp127.0.0.19999# 终端B再运行客户端CtrlC 停服务器看 recv 0 现象附录 B文件uloop_tcp.c/* * uloop_tcp.c —— 课时 17用 uloop 写一个 TCP 客户端 * * 编译gcc -Wall -Wextra -o uloop_tcp uloop_tcp.c -lubox * 运行./uloop_tcp 127.0.0.1 9999 * * 三件事 * ① connect() 连上服务器阻塞式简单直接 * ② 把 fd 交给 uloop 监视服务器发回来什么就打印什么 * ③ 每 3 秒主动发一条消息计数器演示定时 收发在同一个事件循环里 * 服务器关掉后recv 返回 0客户端打印断开信息并退出。 */#includestdio.h#includestdlib.h#includestring.h#includestdint.h#includeunistd.h#includearpa/inet.h#includesys/socket.h#includelibubox/uloop.h#defineBUF_SIZE512staticstructuloop_fdufd;staticstructuloop_timeouttick;/* 每 3 秒发一条消息 */staticintcounter0;/* 服务器发数据来了 */staticvoidon_readable(structuloop_fd*f,unsignedintevents){charbuf[BUF_SIZE1];ssize_tn;(void)events;nrecv(f-fd,buf,BUF_SIZE,0);if(n0){buf[n]\0;printf(← 收到服务器回复%zd 字节%s\n,n,buf);return;}/* recv 返回 0对方关闭了连接返回负数出错 */if(n0){printf(✗ 服务器关闭了连接recv 返回 0客户端退出\n);}else{perror(recv);}uloop_fd_delete(ufd);close(f-fd);uloop_end();}/* 定时器每 3 秒往服务器发一条 */staticvoidon_tick(structuloop_timeout*t){charmsg[64];ssize_tn;(void)t;counter;snprintf(msg,sizeof(msg),第 %d 条消息,counter);nsend(ufd.fd,msg,strlen(msg),0);if(n0){perror(send);}else{printf(→ 已发送%zd 字节%s\n,n,msg);}uloop_timeout_set(tick,3000);/* 重新排下一次3 秒后 */}intmain(intargc,char*argv[]){structsockaddr_inserver;intport;intfd;if(argc3){printf(用法: %s 服务器IP 端口\n,argv[0]);printf(例: %s 127.0.0.1 9999\n,argv[0]);return1;}portatoi(argv[2]);uloop_init();printf(① uloop 初始化完成\n);memset(server,0,sizeof(server));server.sin_familyAF_INET;server.sin_porthtons((uint16_t)port);if(inet_pton(AF_INET,argv[1],server.sin_addr)!1){printf(IP 地址不对%s\n,argv[1]);return1;}/* ② 连接服务器这一步是三次握手和课时 13 一样 */fdsocket(AF_INET,SOCK_STREAM,0);if(fd0){perror(socket);return1;}if(connect(fd,(structsockaddr*)server,sizeof(server))0){perror(connect服务器没开IP/端口对不对);close(fd);return1;}printf(② 已连接到 %s:%d\n,argv[1],port);/* ③ 把已连接的 fd 交给 uloop 监视读事件 */ufd.fdfd;ufd.cbon_readable;uloop_fd_add(ufd,ULOOP_READ);printf(③ 连接已交给 uloop 监视\n);/* ④ 3 秒后开始周期性发送 */tick.cbon_tick;uloop_timeout_set(tick,3000);printf(④ 进入 uloop_run()每 3 秒发一条收到回复就打印按 CtrlC 退出\n);uloop_run();uloop_done();printf(⑤ uloop 结束客户端退出\n);return0;}附录 C文件tcp_echo_server.py#!/usr/bin/env python3课时 17 测试工具TCP 回显服务器收到一行就回一行 用法python3 tcp_echo_server.py [端口] # 端口默认 9999CtrlC 退出 提示按 CtrlC 停掉它正好能观察 C 客户端打印服务器关闭了连接。 importsocketimportsys portint(sys.argv[1])iflen(sys.argv)1else9999srvsocket.socket(socket.AF_INET,socket.SOCK_STREAM)srv.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)srv.bind((0.0.0.0,port))srv.listen(5)print(fTCP 回显服务器已启动监听{port}端口CtrlC 退出)try:whileTrue:conn,addrsrv.accept()print(f客户端{addr[0]}:{addr[1]}已连接)withconn:whileTrue:dataconn.recv(1024)ifnotdata:breaktextdata.decode(utf-8,replace)print(f收到:{text})conn.sendall(fECHO:{text}.encode())print(f客户端{addr[0]}:{addr[1]}断开)exceptKeyboardInterrupt:print(\n服务器退出)finally:srv.close()
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

xberg C 绑定之 ListRenderers:查询渲染器注册表与自定义输出格式实战 2026/9/28 21:22:05

xberg C 绑定之 ListRenderers:查询渲染器注册表与自定义输出格式实战

后端AI 应用NLP 【免费下载链接】xberg Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with …

阅读更多 →
【无标题】我的第一篇博客|开启编程学习之路 2026/9/28 21:22:05

【无标题】我的第一篇博客|开启编程学习之路

大家好,这是我的第一篇博客。先简单做个自我介绍:我是一名大一新生,刚踏入大学校园。在此之前我几乎没有编程基础,对代码世界充满好奇,希望能在这里记录我的学习点滴,见证自己一点点进步。我学习编程的目标…

阅读更多 →
自研远程桌面工具威胁模型与安全设计清单 2026/9/28 21:22:05

自研远程桌面工具威胁模型与安全设计清单

前面四篇把"做什么、怎么搭"讲完了。最后这篇聊最硬核也最该被问的那句话:真出事了怎么办?一个远程桌面把你的桌面画面和键鼠都送出去了,如果中间任何一环被攻破,内容会不会泄露?这篇不喊口号,直…

阅读更多 →
PHP 开源 IM 即时通讯系统效果实测与功能展示 2026/9/28 21:22:05

PHP 开源 IM 即时通讯系统效果实测与功能展示

在搭建社群运营平台时,很多开发者往往陷入一个误区:过分追求功能的堆砌,而忽视了核心交互的流畅度与系统的稳定性。实际落地中,用户并不关心你用了多么前沿的架构,他们在意的是消息能不能秒达、直播卡不卡、付费入群是…

阅读更多 →
【界面心法】别用动画掩盖丢包!撕碎“渲染顺滑”的 UI 幻觉,论图形欺诈与“心跳死锁”的绝对物理真实 2026/9/28 21:22:04

【界面心法】别用动画掩盖丢包!撕碎“渲染顺滑”的 UI 幻觉,论图形欺诈与“心跳死锁”的绝对物理真实

摘要:在纯软件的沙盒里,UI 是为了服务人类视觉的愉悦感。但在面对高压、高速、重负载的工业现场时,上位机界面是人类窥探狂暴物理世界的唯一狭缝。无数跨界开发者迷信于“渲染帧率”,用前端的平滑补帧和动画算法,亲手为…

阅读更多 →
使用 Claude Code 驱动 Model-Optimizer Launcher:模型优化作业的提交、监控与诊断闭环 2026/9/28 21:21:58

使用 Claude Code 驱动 Model-Optimizer Launcher:模型优化作业的提交、监控与诊断闭环

人工智能大模型模型优化模型量化模型压缩 【免费下载链接】Model-Optimizer A unified library of SOTA model optimization techniques like quantization, distillation, pruning, neural architecture search, speculative decoding, etc. It compresses deep learning mode…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉