【Linux】socket网络编程之UDP

【Linux】socket网络编程之UDP
在这里插入图片描述

个人主页~


socket网络编程UDP

一、必备接口

1、接收数据

recvfrom函数用于从套接字接收数据

#include<sys/socket.h>ssize_trecvfrom(int sockfd,void*buf,size_t len,int flags,structsockaddr*src_addr,socklen_t*addrlen);

返回值:返回正数表示成功接收到的数据字节数,返回0表示对方已经关闭了连接(对于TCP),返回-1表示发生错误
sockfd:指定从哪个套接字接收数据
buf:指向一个缓冲区,用于存储接收到的数据
len:指定buf的最大长度
flags:设置接收数据的标志,无标志一般设为0,在这里可以设置非阻塞模式
src_addr:用于存储发送方的地址信息,输出型参数
addrlen:用于指定src_addr结构体的长度,输入输出型参数,在调用 recvfrom 函数之前,需要将其初始化为 src_addr 结构体的最大长度,函数返回时,addrlen 会被更新为实际存储在 src_addr 中的地址信息的长度

2、发送数据

sendto函数用于在无连接的套接字(如 UDP 套接字)上发送数据

#include<sys/socket.h>ssize_tsendto(int sockfd,constvoid*buf,size_t len,int flags,conststructsockaddr*dest_addr,socklen_t addrlen);

返回值:返回正数表示成功发送的数据字节数,返回-1表示发送过程中出现错误
sockfd:指定通过哪个套接字发送数据
buf:指向要发送的数据的缓冲区
len:表示要发送的数据的长度(以字节为单位),即 buf 缓冲区中实际要发送的数据的字节数
flags:设置发送数据的标志,无标志一般设为0,在这里可以设置非阻塞模式
dest_addr:该结构体包含了目标地址的信息
addrlen:表示dest_addr结构体的长度(以字节为单位)

二、实现UDP网络编程

1、服务器

(一)UdpServer.hpp

#pragmaonce#include<iostream>#include<string>#include<strings.h>#include<cstring>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include<functional>#include<unistd.h>// 下面两行都是代表着定义一个类似函数指针的变量func_t,参数和返回值都是string// using func_t = std::function<std::string(const std::string&)>;typedef std::function<std::string(const std::string&)> func_t;//枚举错误类型enum{ SOCKET_ERR=1, BIND_ERR };//定义端口号和ip地址uint16_t defaultport =8080; std::string defaultip ="0.0.0.0";//size用来定义缓冲区大小constint size =1024;classUdpServer{public:UdpServer(constuint16_t&port = defaultport,const std::string &ip = defaultip):sockfd_(0),port_(port),ip_(ip),isrunning_(false){}voidInit(){// 创建udp socket sockfd_ =socket(AF_INET, SOCK_DGRAM,0);if(sockfd_ <0){exit(SOCKET_ERR);}// 定义一个local存储本地地址structsockaddr_in local;//bzero的作用就是将local结构体清零bzero(&local,sizeof(local));//将local的前两个字节也就是它的地址族为AF_INET local.sin_family = AF_INET;//保证我们的端口号是网络字节序列,因为该端口号是要给对方发送的 local.sin_port =htons(port_);//inet_addr函数将ip_转换为in_addr_t类型的IP地址,并存储在local.sin_addr.s_addr local.sin_addr.s_addr =inet_addr(ip_.c_str());//绑定sockfd_到本地地址local上,失败则退出if(bind(sockfd_,(conststructsockaddr*)&local,sizeof(local))<0){exit(BIND_ERR);}}voidRun(func_t func)// 对代码进行分层{//设置服务器开始运行标志 isrunning_ =true;//定义缓冲区存放接收到的数据char inbuffer[size];while(isrunning_){//定义client结构体存储客户端的地址信息structsockaddr_in client; socklen_t len =sizeof(client);//获取客户端信息 ssize_t n =recvfrom(sockfd_, inbuffer,sizeof(inbuffer)-1,0,(structsockaddr*)&client,&len);if(n <0){continue;}//在最后添加字符串描述符'\0' inbuffer[n]=0;//将所有的信息通过func函数处理为echo_string std::string info = inbuffer; std::string echo_string =func(info);//将处理完后的数据发送到客户端sendto(sockfd_, echo_string.c_str(), echo_string.size(),0,(const sockaddr*)&client, len);}}//析构,sockfd_本质上是一个文件描述符一样的东西,用close可以关闭~UdpServer(){if(sockfd_>0)close(sockfd_);}private:int sockfd_;// 网路文件描述符 std::string ip_;// 任意地址bind 0uint16_t port_;// 表明服务器进程的端口号bool isrunning_;// 服务器运行状态};

(二)main.cpp

#include"UdpServer.hpp"#include<memory>#include<cstdio>// 端口号一般是可以随便定义的,但是[0,1023]范围内的端口号一般都是有固定的应用层协议的//所以我们都用1024+的端口号//输入小于1024的端口号就提示重输voidUsage(std::string proc){ std::cout <<"\n\rUsage: "<< proc <<" port[1024+]\n"<< std::endl;}//该函数用于处理接收到的消息,将消息添加到固定的前缀 "Server get a message: " 后面//并将结果输出到控制台 std::string Handler(const std::string &str){ std::string res ="Server get a message: "; res += str; std::cout << res << std::endl;return res;}//该函数用于执行客户端发送的命令,并将命令执行的结果返回给 UDP 服务器//从而实现服务器与客户端之间的交互,让客户端可以在服务器端执行命令并获取结果 std::string ExcuteCommand(const std::string &cmd){ FILE *fp =popen(cmd.c_str(),"r");if(nullptr== fp){perror("popen");return"error";} std::string result;char buffer[4096];while(true){char*ok =fgets(buffer,sizeof(buffer), fp);if(ok ==nullptr)break; result += buffer;}pclose(fp);return result;}// ./udpserver portintmain(int argc,char*argv[]){//在命令行中只带一个参,多带参和少带参都要执行Usageif(argc !=2){Usage(argv[0]);exit(0);}uint16_t port = std::stoi(argv[1]);//智能指针管理 UdpServer 对象的生命周期,确保对象在不再使用时自动释放内存 std::unique_ptr<UdpServer>svr(newUdpServer(port));//初始化并启动服务器 svr->Init(); svr->Run(ExcuteCommand);return0;}

2、客户端

UdpClient.cpp

#include<iostream>#include<cstdlib>#include<unistd.h>#include<strings.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>usingnamespace std;voidUsage(std::string proc){ std::cout <<"\n\rUsage: "<< proc <<" serverip serverport\n"<< std::endl;}intmain(int argc,char*argv[]){//命令行参数不为三个就打印提示信息if(argc !=3){Usage(argv[0]);exit(0);}//获取服务器端口号和服务器ip std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);//下面似曾相识呢,和上面服务器的解释一致structsockaddr_in server;bzero(&server,sizeof(server)); server.sin_family = AF_INET; server.sin_port =htons(serverport); server.sin_addr.s_addr =inet_addr(serverip.c_str()); socklen_t len =sizeof(server);int sockfd =socket(AF_INET, SOCK_DGRAM,0);if(sockfd <0){ cout <<"socker error"<< endl;return1;}//客户端套接字实际上也需要绑定,但通常不需要用户显式地进行绑定//操作系统会在客户端首次发送数据时自动为其分配一个可用的端口号进行绑定 string message;char buffer[1024];while(true){ cout <<"Please Enter@ ";getline(cin, message);//将消息发送到服务器sendto(sockfd, message.c_str(), message.size(),0,(structsockaddr*)&server, len);//接收信息并打印structsockaddr_in temp; socklen_t len =sizeof(temp); ssize_t s =recvfrom(sockfd, buffer,1023,0,(structsockaddr*)&temp,&len);if(s >0){ buffer[s]=0; cout << buffer << endl;}}close(sockfd);return0;}

最终我们实现的就是一个客户端可以通过指令操控服务器,然后将服务器应该输出的结果打印到客户端

在这里插入图片描述

今日分享就到这里了~

在这里插入图片描述

Read more

用 OpenClaw + 飞书,快速搭建 5 个可协作的 AI 助理团队

多个飞书机器人 + 独立工作空间 + 互相协作 = 专业化分工的 AI 助理团队 写在前面 如何用 OpenClaw 搭建一套多 Agent 系统,让 AI 助理各司其职、协同工作?通过 OpenClaw 多 Agent 架构,你可以实现: * 多个独立的飞书机器人,每个人设不同 * 各自独立的工作空间,数据完全隔离 * 可以互相协作,通过 agentToAgent 通信 * 共享长期记忆,跨渠道信息同步 本文将详细介绍如何在腾讯云服务器上,用 OpenClaw 搭建一套飞书多 Agent 系统,包括完整配置流程、常见问题解决方案和实战协作案例。 目录 1. 为什么需要多 Agent 2. 前置准备 3. 5 个 Agent

By Ne0inhk
【Linux】screen 命令创建会话 保持后台运行

【Linux】screen 命令创建会话 保持后台运行

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕Linux这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获! 文章目录 * Linux 下 screen 命令创建会话保持后台运行 🖥️ * 什么是 screen 命令?🧭 * screen 的核心特性 * screen 的工作原理 * screen 命令的安装与基本使用 🛠️ * 安装 screen * Ubuntu/Debian 系统: * CentOS/RHEL/Fedora 系统: * Arch Linux 系统: * 启动 screen 会话 * 基本操作界面 * 退出 screen 会话 * 方法一:使用快捷键 * 方法二:使用命令 * screen 会话的创建与管理

By Ne0inhk
HarmonyOS应用开发实战(基础篇)Day06-《常见组件》

HarmonyOS应用开发实战(基础篇)Day06-《常见组件》

常见组件 * Image(图像组件) * 基本用法 * 核心属性 * 使用场景 * 注意事项 * Text(文本组件) * 基本用法 * 核心特性 * 使用场景 * 最佳实践 * TextInput(输入框组件) * 基本用法 * 输入类型(`type` 属性) * 密码输入示例 * 其他重要属性 * 安全建议 * Button(按钮组件) * 基本用法 * 类型与样式 * 交互增强 * 使用场景 * Swiper(轮播组件) * 基本结构 * 核心属性 * 注意事项 * List(列表组件) * 基本用法 * 关键特性 * 性能优化 * 验证要点 * Scroll(滚动容器) * 使用条件 * 嵌套限制 * 行为验证 * 总结 Image(图像组件) Image 是 ArkUI

By Ne0inhk
【openclaw+imessage】【免费无限流量】集成方案,支持iphone手机+macos

【openclaw+imessage】【免费无限流量】集成方案,支持iphone手机+macos

🚀 手把手打通 iMessage 私有 API:用 BlueBubbles + OpenClaw 构建本地 AI 短信中枢(技术深度解析) ⚠️ 警告:本文涉及 macOS 私有 API 调用与本地代理配置,属于高阶操作。苹果已明确表示将在 2026 年 6 月 终止此类非合规应用支持,请抓紧窗口期体验。 🔥 核心目标 通过 BlueBubbles Server v1.9.9 调用 macOS 原生 Messages.app 的私有接口,结合 OpenClaw 实现 AI 自动收发 iMessage——无需越狱、无需公网 IP,纯局域网闭环运行,却能通过IMeesage安全地让移动设备和openclaw通讯!通信通道采用苹果加密的IMessage,

By Ne0inhk