【计网】UDP Echo Server与Client实战:从零开始构建简单通信回显程序
目录
前言:
1.实现udpserver类
1.1.创建udp socket 套接字 --- 必须要做的
socket()讲解
代码实现:编辑
代码讲解:
1.2.填充sockaddr_in结构
代码实现:
代码解析:
1.3.bind sockfd和网络信息(IP + Port)
bind函数解析:
代码展现:
1.4.总代码
2.echo_server主体实现
2.1. 我们要让server先收数据
recvfrom 函数
2.2. 我们要将server收到的数据,发回给对方
sendto函数
2.3.代码
3.client客户端的实现
3.1.创建socket
3.2.填充sockaddr_in结构
3.3.client要不要bind?
3.4.直接通信
3.5.代码
4.效果展现
server端为什么不需要IP端口?
前言:
我们之前讲解了关于socket编程的一些基础知识和接口函数,今天我们就来小试牛刀一下,自己编写一个简单的echo_server程序,将客户端的数据在服务端打印出来(利用udp协议实现)!
1.实现udpserver类
1.1.创建udp socket 套接字 --- 必须要做的
socket()讲解
NAME
socket - create an endpoint for communication
SYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
socket函数是一个系统调用函数,用于创建一个新的套接字。该函数返回一个套接字文件描述符,如果创建失败则返回-1。
参数讲解:
domain: 选择通信方式 — 本地通信与网络通信
type: 选择协议— UDP/TCP
protocol: 默认使用0、
返回值是创建的socket文件操作符socketfd
代码实现:
代码讲解:
-
AF_INET
:这是socket()
函数的第一个参数,指定了地址族(Address Family)。AF_INET
表示使用IPv4地址,它是Internet地址族的简写。 -
SOCK_DGRAM
:这是socket()
函数的第二个参数,指定了套接字类型。SOCK_DGRAM
表示数据报套接字,这是一种无连接的、固定最大长度的消息服务。它常用于UDP(用户数据报协议)通信。 -
0
:这是socket()
函数的第三个参数,通常用于指定协议。当使用AF_INET
和SOCK_DGRAM
时,这个参数通常为0,表示自动选择对应的协议(在这种情况下是UDP)。
1.2.填充sockaddr_in结构
sockaddr_in结构体通常用于网络编程中表示IPv4地址和端口便于我们进行网络通信。
sockaddr_in
是一个在<netinet/in.h>
(或<arpa/inet.h>
,取决于您的系统)头文件中定义的结构体,用于存储IPv4地址和端口信息。
代码实现:
代码解析:
htons()函数将主机序列,转成网络序列,填充sockaddr_in结构
1.3.bind sockfd和网络信息(IP + Port)
bind函数解析:
NAME
bind - bind a name to a socketSYNOPSIS
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
bind绑定 ,将socket文件与IP地址绑定和端口号,也就是将进程与文件进行绑定。这样当数据包到达该端口和地址时,操作系统知道应该将数据传递给哪个应用程序。
代码展现:
1.4.总代码
void InitServer(){// 1. 创建udp socket 套接字 --- 必须要做的_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(FATAL, "socket error, %s, %d\n", strerror(errno), errno);exit(SOCKET_ERROR);}LOG(INFO, "socket create success, sockfd: %d\n", _sockfd);// 2.0 填充sockaddr_in结构struct sockaddr_in local; // struct sockaddr_in 系统提供的数据类型。local是变量,用户栈上开辟空间。int a = 100; a = 20;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(_port); // port要经过网络传输给对面,先到网络,_port:主机序列-> 主机序列,转成网络序列// a. 字符串风格的点分十进制的IP地址转成 4 字节IP// b. 主机序列,转成网络序列// in_addr_t inet_addr(const char *cp) -> 同时完成 a & b// local.sin_addr.s_addr = inet_addr(_ip.c_str()); // "192.168.3.1" -> 字符串风格的点分十进制的IP地址 -> 4字节IPlocal.sin_addr.s_addr = INADDR_ANY; // htonl(INADDR_ANY);// 2.1 bind sockfd和网络信息(IP(?) + Port)int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));if (n < 0){LOG(FATAL, "bind error, %s, %d\n", strerror(errno), errno);exit(BIND_ERROR);}LOG(INFO, "socket bind success\n");}
2.echo_server主体实现
2.1. 我们要让server先收数据
recvfrom
函数
用于从一个套接字(由 _sockfd
标识)接收数据。
NAME
recv, recvfrom, recvmsg - receive a message from a socketSYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
一般使用recvfrom函数,从socket文件中获取数据,并可以得到发送者的信息
- sockfd:从指定的socket文件中读取数据
- buf:缓冲区,将数据读取到这里
- len:缓冲区的长度
- src_addr:输出型参数,获取发送者的信息
- addrlen:输出型参数,获取发送者结构体的长度
2.2. 我们要将server收到的数据,发回给对方
sendto函数
NAME
send, sendto, sendmsg - send a message on a socket
SYNOPSIS
#include <sys/types.h>
#include <sys/socket.h>ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
- sockfd: socket文件操作符,绑定了确定的IP地址与端口,保证数据按照该文件绑定的方式进行通信
- buf:指向包含要发送数据的缓冲区的指针。这个缓冲区应该已经填充了您想要发送的数据。
- len:buf指向的缓冲区中数据的长度,以字节为单位。这个值告诉sendto函数要发送多少字节的数据。
- flags:这个参数通常设置为0,表示没有特殊的发送选项。不过,它可以是一些标志的组合,比如 MSG_CONFIRM(用于TCP,确认路径是有效的)或MSG_DONTROUTE(数据不应该通过网关发送)。
- dest_addr:指向sockaddr结构体的指针,该结构体包含了数据将要发送到的目标地址和端口。对于IPv4,这通常是一个sockaddr_in结构体,而对于IPv6,则是一个sockaddr_in6结构体。
- addrlen:dest_addr指向的sockaddr结构体的大小,以字节为单位。这确保了无论在何种平台上,传递给sendto的都是正确的字节大小。
我们一般使用sendto函数来进行发送数据
2.3.代码
void Start(){// 一直运行,直到管理者不想运行了, 服务器都是死循环// UDP是面向数据报的协议_isrunning = true;while (true){char buffer[1024];struct sockaddr_in peer;socklen_t len = sizeof(peer); // 必须初始化成为sizeof(peer)// 1. 我们要让server先收数据ssize_t n = recvfrom(_sockfd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);if (n > 0){buffer[n] = 0;InetAddr addr(peer);LOG(DEBUG, "get message from [%s:%d]: %s\n", addr.Ip().c_str(), addr.Port(), buffer);// 2. 我们要将server收到的数据,发回给对方sendto(_sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)&peer, len);}}_isrunning = false;}
3.client客户端的实现
3.1.创建socket
跟server端一样,第一步首先要上来创建socket,
3.2.填充sockaddr_in结构
这一步骤也是跟server端一样。
3.3.client要不要bind?
一定要,client也要有自己的IP和PORT。要不要显式[和server一样用bind函数]的bind?不能!不建议!!
- 如何bind呢?udp client首次发送数据的时候,OS会自己自动随机的给client进行bind ---为什么?防止client port冲突。比如抖音和淘宝使用了同一个端口造成冲突!要bind,必然要和port关联!
- 什么时候bind呢?首次发送数据的时候
3.4.直接通信
流程如下:
- 客户端先输入数据,发送到服务端
- 服务端接收数据
- 服务端再将接收到的数据发送给客户端
- 最后客户端在屏幕回显出自己原本发送的数据
3.5.代码
void Usage(std::string proc)
{std::cout << "Usage:\n\t" << proc << " serverip serverport\n"<< std::endl;
}// ./udpclient serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(1);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);// 1. 创建socketint sockfd = socket(AF_INET, SOCK_DGRAM, 0);if(sockfd < 0){std::cerr << "socket error" << std::endl;}// 2. client要不要bind?一定要,client也要有自己的IP和PORT。要不要显式[和server一样用bind函数]的bind?不能!不建议!!// a. 如何bind呢?udp client首次发送数据的时候,OS会自己自动随机的给client进行bind --- //为什么?防止client port冲突。比如抖音和淘宝使用了同一个端口造成冲突!要bind,必然要和port关联!// b. 什么时候bind呢?首次发送数据的时候// 构建目标主机的socket信息struct sockaddr_in server;memset(&server, 0, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport);server.sin_addr.s_addr = inet_addr(serverip.c_str());std::string message;// 2. 直接通信即可while(true){std::cout << "Please Enter# ";std::getline(std::cin, message);sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&server, sizeof(server));struct sockaddr_in peer;socklen_t len = sizeof(peer);char buffer[1024];ssize_t n = recvfrom(sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);if(n > 0){buffer[n] = 0;std::cout << "server echo# " << buffer << std::endl;}}return 0;
}
4.效果展现
成功!
server端为什么不需要IP端口?
因为server默认绑定的就是0.0.0.0,代表绑定自己的所有网卡信息,所以就不要我们自己手动填写啦。
相关文章:
【计网】UDP Echo Server与Client实战:从零开始构建简单通信回显程序
目录 前言: 1.实现udpserver类 1.1.创建udp socket 套接字 --- 必须要做的 socket()讲解 代码实现:编辑 代码讲解: 1.2.填充sockaddr_in结构 代码实现: 代码解析: 1.3.bind sockfd和…...
微服务网关Zuul
一、Zuul简介 Zuul是Netflix开源的微服务网关,包含对请求的路由和过滤两个主要功能。 1)路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。 2)过滤功能:负责对请求的过程…...
BuildCTF线上赛WP
Build::CTF flag不到啊战队--WP 萌新战队,还请多多指教~ 目录 Build::CTF flag不到啊战队--WP Web ez!http find-the-id Pwn 我要成为沙威玛传奇 Misc what is this? 一念愚即般若绝,一念智即般若生 别真给我开盒了哥 四妹,你听…...
《使用Gin框架构建分布式应用》阅读笔记:p143-p207
《用Gin框架构建分布式应用》学习第10天,p143-p207总结,总计65页。 一、技术总结 1.auth0 本人实际工作中未遇到过,mark一下,参考:https://auth0.com/。 2.使用template (1)c.File() (2)router.Static() (3)rou…...
华为网络管理配置实例
目录 组网需求 数据规划 配置思路 操作步骤 结果验证 配置脚本 管理员可以通过eSight网管系统对FW进行监控和管理,接收FW的告警。 组网需求 如图1所示,某企业在网络边界处部署了FW作为安全网关,并部署了eSight网管系统对网络设备进行集中…...
大语言模型数据处理方法(基于llama模型)
文章目录 前言一、基于huggingface的DataCollatorForSeq2Seq方法解读1、DataCollatorForSeq2Seq方法2、batch最长序列填充3、指定长度填充二、构建大语言模型数据加工模块1、数据读取2、数据加工1、数据格式2、预训练(pretrain)数据加工3、微调(sft)数据加工①、sft数据加工…...
爱奇艺大数据多 AZ 统一调度架构
01# 导语 爱奇艺大数据技术广泛应用于运营决策、用户增长、广告分发、视频推荐、搜索、会员营销等场景,为公司的业务增长和用户体验提供了重要的数据驱动引擎。 多年来,随着公司业务的发展,爱奇艺大数据平台已积累了海量数据,这…...
【C++篇】栈的层叠与队列的流动:在 STL 的韵律中探寻数据结构的优雅之舞
文章目录 C 栈与队列详解:基础与进阶应用前言第一章:栈的介绍与使用1.1 栈的介绍1.2 栈的使用1.2.1 最小栈1.2.2 示例与输出 1.3 栈的模拟实现 第二章:队列的介绍与使用2.1 队列的介绍2.2 队列的使用2.2.1 示例与输出 2.3 队列的模拟实现2.3.…...
使用 Flask 实现简单的登录注册功能
目录 1. 引言 2. 环境准备 3. 数据库设置 4. Flask 应用基本配置 5. 实现用户注册 6. 实现用户登录 7. 路由配置 8. 创建前端页面 9. 结论 1. 引言 在这篇文章中,我们将使用 Flask 框架创建一个简单的登录和注册系统。Flask 是一个轻量级的 Python Web 框架…...
计算机毕业设计Python+大模型微博情感分析 微博舆情预测 微博爬虫 微博大数据 舆情分析系统 大数据毕业设计 NLP文本分类 机器学习 深度学习 AI
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 《Python大模型微博情感分析…...
CTF--Misc题型小结
(萌新笔记,多多关照,不足之处请及时提出。) 不定时更新~ 目录 密码学相关 文件类型判断 file命令 文件头类型 strings读取 隐写术 尺寸修改 文件头等缺失 EXIF隐写 thumbnail 隐写 文件分离&提取 binwalk foremo…...
深度学习系列——RNN/LSTM/GRU,seq2seq/attention机制
1、RNN/LSTM/GRU可参考: https://zhuanlan.zhihu.com/p/636756912 (1)对于这里面RNN的表示中,使用了输入x和h的拼接描述,其他公式中也是如此 (2)各符号图含义如下 2、关于RNN细节,…...
通过call指令来学习指令摘要表的细节
E8 cw cw 表示E8后面跟随2 字节 (什么数不知道) rel16 指在与指令同一代码段内的相对地址偏移 D ,指向Instruction Operand Encoding 表中的D列, 他告诉我们 操作数1 是一个0FFSET N.S. 在64位模式下,某些指令需要使用“地址覆盖前缀”(address over…...
10分钟使用Strapi(无头CMS)生成基于Node.js的API接口,告别繁琐开发,保姆级教程,持续更新中。
一、什么是Strapi? Strapi 是一个开源的无头(headless) CMS,开发者可以自由选择他们喜欢的开发工具和框架,内容编辑人员使用自有的应用程序来管理和分发他们的内容。得益于插件系统,Strapi 是一个灵活的 C…...
创建插件 DLL 项目
Step 1: 创建插件 DLL 项目 在 Visual Studio 中创建一个新的 DLL 项目,并添加以下文件和代码。 头文件:CShapeBase.h cpp 复制代码 #pragma once #include <afxwin.h> // MFC 必需头文件 #include <string> #include <vector> #i…...
OpenCV双目相机外参标定C++
基于OpenCV库实现双目测量系统外参标定过程。通过分析双目测量系统左右相机拍摄的棋盘格标定板图像,包括角点检测、立体标定、立体校正和畸变校正的步骤,获取左右相机的相对位置关系和姿态。 a.检测每张图像中的棋盘格角点,并进行亚像素级精…...
【GESP】C++一级练习BCQM3055,4位数间隔输出
一级知识点取余、整除运算和格式化输出知识点应用。其实也可以用string去处理,那就属于GESP三级的知识点范畴了,孩子暂未涉及。 题目题解详见:https://www.coderli.com/gesp-1-bcqm3055/ https://www.coderli.com/gesp-1-bcqm3055/https://w…...
纯血鸿蒙的最难时刻才开始
关注卢松松,会经常给你分享一些我的经验和观点。 纯血鸿蒙(HarmonyOS NEXT)也正式发布了,绝对是一个历史性时刻,但最难的鸿蒙第二个阶段,也就是生态圈的建设,才刚刚开始。 目前,我劝你现在不要升级到鸿蒙…...
记一个mysql的坑
数据库表user, 存在一个name字段,字段为varchar类型 现在user表有这么两条记录: idnameageclass1NULL18一班2lisi20二班 假如我根据下面这一条件去更新,更新成功数据行显示为0 update user set age 19 where age 18 and class “一班”…...
Java中的设计模式:单例模式详解
摘要 单例模式(Singleton Pattern)是Java中最常用的设计模式之一,属于创建型模式。它的主要目的是确保一个类在系统中只有一个实例,并提供一个全局访问点来访问该实例。 1. 单例模式的定义 单例模式确保一个类只有一个实例&…...
NanoTrack原理与转tensorrt推理
文章目录 前言一、NanoTrack 工作原理二、运行demo与转换tensorrt模型2.1 运行pt模型demo2.2 转onnx模型2.3 转tensorrt模型2.4 运行trt模型推理 三、推理速度对比总结 前言 NanoTrack 是一种轻量级且高效的目标跟踪算法,基于Siamese网络架构,旨在在资源…...
YOLO11改进 | 卷积模块 | 卷积模块替换为选择性内核SKConv【附完整代码一键运行】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 本文给大家带来的教程是将YOLO11的卷积替…...
CentOS进入单用户模式进行密码重置
一、单用户模式介绍 单用户模式是一种特殊的启动模式,主要用于系统维护和故障排除。在单用户模式下,系统以最小化的状态启动,只有最基本的系统服务会被加载,通常只有root用户可以登录。这种模式提供了对系统的完全控制࿰…...
bitpoke- mysql-operator cluster
sidecar版本只支持到8.0.35,35可以支持到mysql8.0.35 . 默认镜像是5.7的。需要自己打sidecar的镜像: # Docker image for sidecar containers # https://github.com/bitpoke/mysql-operator/tree/master/images/mysql-operator-sidecar-8.0 # 参考5…...
第5课 基本数据类型
一、数据类型的诞生 在Python的世界里,万物皆对象,每个对象都有自己的若干属性,每一个属性都能描述对象的某一个方面。就像我们每个人,都有自己的身高、年龄、姓名、性别等很多方面的信息,这里的身高、年龄、姓名、性…...
OceanBase 首席科学家阳振坤:大模型时代的数据库思考
2024年 OceanBase 年度大会 即将于10月23日,在北京举行。 欢迎到现场了解更多“SQL AI ” 的探讨与分享! 近期,2024年金融业数据库技术大会在北京圆满举行,聚焦“大模型时代下数据库的创新发展”议题,汇聚了国内外众多…...
国内知名的几个镜像源
在国内,有许多常用的Python库镜像源可以帮助加速库的下载。以下是几个知名的镜像源: 1. 清华大学TUNA协会 网址: https://pypi.tuna.tsinghua.edu.cn/simple命令示例:pip install numpy --index-url https://pypi.tuna.tsinghua.edu.cn/simple2. 阿里云…...
海外著名新闻门户媒体软文发稿之华盛顿独立报-大舍传媒
在当今全球化的时代,信息传播的速度和范围达到了前所未有的程度。对于企业和个人而言,如何在国际舞台上有效地展示自己、传递信息,成为了一项至关重要的任务。而海外媒体发稿,特别是通过像华盛顿独立报这样的知名新闻门户…...
青少年编程与数学 02-002 Sql Server 数据库应用 13课题、函数的编写
青少年编程与数学 02-002 Sql Server 数据库应用 13课题、函数的编写 课题摘要:一、函数内置函数用户定义的函数 (User-Defined Functions, UDFs)使用示例主要特点 二、内置函数数学函数(Mathematical Functions)字符串函数(String Functions…...
关于LaTeX的floatrow包导入后标题无法直接放到浮动体上方
排版一个文章,标题怎么弄都弄不到表格上方,经过阅读帮助文档才发现问题。又是一个坑。 标题位置控制 使用floatrow包之后,类似 \begin{table}[htbp]\caption{xxx。}\label{table1}\centering\begin{tabular}{lcccc}\toprule& \multicol…...
银行门户网站建设方案/企业推广
1、NSArray/NSDictionary ------> strong temp和self.arr是同一地址。 2、NSArray/NSDictionary ------->copy temp和self.arr也是同一地址。 3、NSMutableArray/NSMutableDictionary -------->strong temp和self.arr是同一地址。 4、NSMutableArray/NSMutableDictio…...
南京哪家网络公司做网站优化好/关键词优化排名平台
C中的IO类(iostream, fstream, stringstream)小结 参考网址:https://blog.csdn.net/stpeace/article/details/44763009 以前学习C的时候, 总是囫囵吞枣地理解cin, cout等东东, 最近又在复习C, 复习到IO类这一章节的时候, 有点感…...
做网站用Linux还是win/个人网页模板
网络编程(c/s)与网站编程(b/s)的区别?网站编程是编写网页html,jsp,servelet等,只需要编写一端(server端),不需要编写client端,已经编写好了网络编程相对底层一些,服务端和客户端都需要编写,比如说QQ,msn,飞秋。网络编程…...
惠州住房和建设局网站/亚马逊市场营销案例分析
单片机的ADC接口属于模数转换接口,将外部的模拟量信号转化为数字信号,单片机属于数字器件,需将模拟信号转化为数字信号才能够为单片机处理。目前市场的很多单片机都自带ADC转换接口,若无ADC转换接口,可以使用ADC数模转…...
网站生成静态页面工具/爱站小工具
lambda表达式是C11中引入的一项新技术,利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读。但是从本质上来讲,lambda表达式只是一种语法糖,因为所有其能完成的工作都可以用其它稍…...
济南市建设信用网站/c++线上培训机构哪个好
数值分析里面经常会涉及到用MATLAB程序实现用列主元消去法分别解方程组Axb具体的方法和代码以如下方程(3x3矩阵)为例进行说明:用列主元消去法分别解方程组Axb,用MATLAB程序实现:(1)1、 实现该方程的解的MATLAB代码可以分为两种,一…...