Linux_实现UDP网络通信
目录
1、实现服务器的逻辑
1.1 socket
1.2 bind
1.3 recvfrom
1.4 sendto
1.5 服务器代码
2、实现客户端的逻辑
2.1 客户端代码
3、实现通信
结语
前言:
在Linux下,实现传输层协议为UDP的套接字进行网络通信,网络层协议为IPv4,需要用到的接口有以下4个:socket、bind、recvfrom、sendto。具体实现方法:在云服务器上创建一个服务器进程和一个客户端进程,让客户端向服务器发送消息,并且服务器收到消息后可以反馈给对方。
示意图如下:

1、实现服务器的逻辑
按照以下函数的调用顺序,即可实现服务器方的UDP通信。
1.1 socket
首先明确使用IPv4协议和UDP协议后,先调用接口socket,让其返回一个网络文件描述符给到我们,socket函数介绍如下:
#include <sys/types.h>
#include <sys/socket.h>int socket(int domain, int type, int protocol);
//domain表示网络协议族,AF_INET为IPv4,AF_INET6为IPv6
//type表示传输层协议,SOCK_STREAM为TCP,SOCK_DGRAM为UDP
//protocol表示指定特定的协议,一般前两个参数的协议足矣,这里填0即可//调用成功返回一个类型文件描述符的网络描述符,失败返回-1
1.2 bind
定义一个struct sockaddr_in类型的变量,该变量的作用是为调用bind接口做准备,该变量里面有3个信息需要填写,分别是:1、传输层协议,2、为该进程设置的端口号,3、该主机的IP地址。其中,端口号和IP地址需要对其转换成大端字节序,因为网络规定传输的数据采用大端字节序传输,这里介绍两个接口可以帮助我们直接将端口号和IP转换成大端字节序,接口介绍如下:
#include <arpa/inet.h>uint16_t htons(uint16_t hostshort);//常用来转换端口号
//将主机字节序转换成网络字节序并返回#include <arpa/inet.h> unsigned long inet_addr(const char *cp);//常用来转换IP地址
//如果cp指向的是IP地址的字符串形式,那么会将其转换为网络字节序的IP地址
//并且以无符号的长整型返回
待struct sockaddr_in类型的变量的字段填写完毕后,下一步就是进行绑定操作,绑定的目的是将socket返回的网络描述符与struct sockaddr_in类型的变量进行绑定,即可以通过网络描述符来找到对应的ip地址以及端口号,简单来说,通过网络描述符就能找到对应主机的对应进程。
接着就是调用bind接口进行绑定了,bind接口介绍如下:
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
//socket表示要绑定的网络描述符
//address表示指向struct sockaddr类型的变量
//address_len表示address指向变量的大小//调用成功返回0,失败返回-1
1.3 recvfrom
recvfrom接口有点类似文件操作中的read接口,都带有接收的意思。recvfrom接口用于从网络描述符中读取对方主机发送的数据,并且还可以将对方主机的地址信息(IP和端口号)给记录下来,该接口的介绍如下:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
//sockfd表示读取的网络描述符
//buf表示存放读取数据的目标缓冲区
//len表示期望读取内容的大小
//flag表示设置该函数的模式,比如阻塞或非阻塞,通常设为0表阻塞
//src_addr是个输出型参数,用于保存发送方的地址信息
//addrlen表示src_addr指向变量的大小//成功返回接收的字节数,若sockfd关闭返回0,失败返回-1
1.4 sendto
如果说recvfrom接口类似read接口,那么sendto就好比write接口,他能够往网络文件描述符内写入数据,即发送方就是调用sendto接口向接收方发送数据,sendto和recvfrom相互搭配实现网络通信。sendto介绍如下:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
//sockfd表示要发送数据的文件描述符
//buf表示发送缓冲区
//len表示要发送数据的长度
//flag表示设置该函数的模式,比如阻塞或非阻塞,通常设为0表阻塞
//dest_addr指向的结构体里包含接收方的IP和端口号,依靠他们才能找到接收方
//addrlen表示dest_addr指向结构体的大小
1.5 服务器代码
将服务器封装成一个类,并把服务器的端口号、ip地址、网络描述符作为该类的成员变量,这样就可以对上述功能逻辑进行分层了,服务器类代码如下:
#pragma once#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 <cstdio>
#include <unistd.h>
using namespace std;uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";
const int size = 1024;class UdpServer{
public:UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip):sockfd_(0), port_(port), ip_(ip){}void Init(){// 1. 创建udp socketsockfd_ = socket(AF_INET, SOCK_DGRAM, 0); printf("socket create success, sockfd: %d\n", sockfd_);// 2. bind socketstruct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_); local.sin_addr.s_addr = inet_addr(ip_.c_str()); bind(sockfd_, (const struct sockaddr *)&local, sizeof(local));printf("bind success, errno: %d, \err string: %s\n", errno, strerror(errno));}void Run() // 对代码进行分层{char inbuffer[size];while(true){struct sockaddr_in client;socklen_t len = sizeof(client);//服务器先接收消息ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1,0, (struct sockaddr*)&client, &len);cout<<"客户端说:"<<inbuffer<<endl;inbuffer[n] = 0;std::string info = inbuffer;std::string echo_string = "服务器的回答:"+info;//再反馈消息sendto(sockfd_, echo_string.c_str(), echo_string.size(), 0, (const sockaddr*)&client, len);}}~UdpServer(){if(sockfd_>0) close(sockfd_);//关闭描述符}
private:int sockfd_; // 网路文件描述符std::string ip_; // ip地址uint16_t port_; // 服务器端口号
};
该服务器的逻辑是先接收客户端发送的消息,然后利用recvfrom函数保存客户端的地址信息,再使用sendto函数对客户端进行信息的反馈。
2、实现客户端的逻辑
客户端逻辑和服务器逻辑几乎一样,第一步必须调用socket创建网络描述符,但是第二步客户端不需要进行bind绑定,因为服务器之所以需要绑定是因为服务器必须手动自定义一个端口号,目的就是要让该端口号可见,以便让客户端知道该端口号,这样客户端才能通过该端口号定位服务器。而客户端不需要自定义端口号,因为客户端的主要任务是给服务器发送信息,这个过程服务器是不需要知道客户端的端口号也可以接收客户端的信息,因此客户端的端口号只需要保证其唯一性即可,即交给操作系统来生成,当首次发送数据的时候操作系统就会为客户端生成端口号。
2.1 客户端代码
客户端代码如下:
#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>using namespace std;void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " serverip serverport\n"<< std::endl;
}// ./udpclient serverip serverport
int main(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]);struct sockaddr_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());//转换网络字节序// 1. socket拿到网络描述符int sockfd = socket(AF_INET, SOCK_DGRAM, 0);socklen_t len = sizeof(server);string message;char buffer[1024];while (true){cout << "Please Enter@ ";getline(cin, message);//2. 向服务器发送信息sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, len);struct sockaddr_in temp;socklen_t len = sizeof(temp);//3. 打印来自服务器的信息recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);cout << buffer << endl;}close(sockfd);//关闭文件描述符return 0;
}
3、实现通信
实现通信的前提是让服务器以进程的形式跑起来,然后再让客户端也以进程的形式跑起来,因为网络通信的本质就是进程间通信,而上述代码中客户端本身就是在main函数中执行的,所以此时客户端可以直接运行,但是服务器还只是个类,因此现在只需要用服务器类实现一个main函数,即可完成两个进程的运行。
服务器进程代码如下:
#include "UDPser.hpp"
#include <memory>
#include <cstdio>void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " port[1024+]\n" << std::endl;
}// ./udpserver port
int main(int argc, char *argv[])
{if(argc != 2){Usage(argv[0]);exit(0);}//从命令行参数拿到端口号uint16_t port = std::stoi(argv[1]);std::unique_ptr<UdpServer> svr(new UdpServer(port));svr->Init();svr->Run();return 0;
}
运行结果:

从结果可以看到目前可以正常的进行客户端与服务器之间的通信。
结语
以上就是关于实现UDP网络通信的讲解,实现UDP的核心在于对套接字的理解以及相关接口的逻辑使用,其实只需要记住只要涉及到网络通信,那么socket和bind函数是必须在最开始就调用的。
最后如果本文有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!!
相关文章:
Linux_实现UDP网络通信
目录 1、实现服务器的逻辑 1.1 socket 1.2 bind 1.3 recvfrom 1.4 sendto 1.5 服务器代码 2、实现客户端的逻辑 2.1 客户端代码 3、实现通信 结语 前言: 在Linux下,实现传输层协议为UDP的套接字进行网络通信,网络层协议为IPv4&am…...
C# 代理模式
栏目总目录 概念 代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。在代理模式中,我们创建一个具有现有对象(称为“真实对象”或“被代理对象”)相同功能的代理对象。代理对象可以在客户端和目标对…...
【1】Python机器学习之基础概念
1、什么是机器学习 最早的机器学习应用——垃圾邮件分辨 传统的计算机解决问题思路: 编写规则,定义“垃圾邮件”,让计算机执行对于很多问题,规则很难定义规则不断变化 机器学习在图像识别领域的重要应用: 人脸识别…...
HashMap源码解析
目录 一:put方法流程 二:get方法 三:扩容机制 一:put方法流程 public V put(K key, V value) {return putVal(hash(key), key, value, false, true); }final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {No…...
[Javascript】前端面试基础3【每日学习并更新10】
Web开发中会话跟踪的方法有那些 cookiesessionurl重写隐藏inputip地址 JS基本数据类型 String:用于表示文本数据。Number:用于表示数值,包括整数和浮点数。BigInt:用于表示任意精度的整数。Boolean:用于表示逻辑值…...
C++自定义字典树结构
代码 #include <iostream> using namespace std;class TrieNode { public:char data;TrieNode* children[26];bool isTerminal;TrieNode(char ch){data ch;for (int i 0; i < 26; i){children[i] NULL;}isTerminal false;} }; class Trie { public:TrieNode* ro…...
dockerfile部署wordpress
1.将容器直接提交成镜像 [rootlocalhost ~]# docker commit 8ecc7f6b9c12 nginx:1.1 sha256:9a2bb94ba6d8d952527df616febf3fbc8f842b3b9e28b7011b50c743cd7b233b [rootlocalhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx …...
CSS(二)——CSS 背景
CSS 背景 CSS 背景属性用于定义HTML元素的背景。 CSS 背景属性 Property描述background简写属性,作用是将背景属性设置在一个声明中。background-attachment背景图像是否固定或者随着页面的其余部分滚动。background-color设置元素的背景颜色。background-image把…...
开机出现grub无法进入系统_电脑开机出现grub解决方法
最近有小伙伴问我电脑开机出现grub无法进入系统怎么回事?电脑开机出grub的情况有很多,电脑上安装了Linux和Win10双系统,但是由于格式化删除了Linux之后,结果win10开机了之后,直接显示grub>,无法…...
uboot 设置bootargs配置内核网络挂载根文件系统
uboot 设置bootargs配置内核网络挂载根文件系统 uboot设置bootargs env set bootargs "mem256M consolettyAMA0,115200 root/dev/nfs init/linuxrc nfsrootnfs主机地址:nfs路径/busybox/rootfs_glibc_arm64,prototcp rw nfsvers3 rootwait ip板子地址:nfs主机地址:网关:2…...
Vue3+.NET6前后端分离式管理后台实战(三十一)
1,Vue3.NET6前后端分离式管理后台实战(三十一)...
22集 如何minimax密钥和groupid-《MCU嵌入式AI开发笔记》
22集 如何获取minimax密钥和groupid-《MCU嵌入式AI开发笔记》 minimax密钥获取 https://www.minimaxi.com/platform 进入minimax网站,注册登录后,进入“账户管理”, 然后再点击“接口密钥”,然后再点击“创建新的密钥”。 之…...
决策树的概念
决策树的概念 决策树是一种监督学习算法,主要用于分类任务。它通过构建一棵树结构模型来进行预测,其中每个内部节点表示一个特征属性上的判断条件,每条边代表一个判断结果对应的分支,而叶节点则代表最终的类别标签。 应用领域 …...
C++《类和对象》(中)
一、 类的默认成员函数介绍二、构造函数 构造函数名与类同名内置类型与自定义类型析构函数拷贝构造函数 C《类和对象》(中) 一、 类的默认成员函数介绍 默认成员函数就是⽤⼾没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。 那么我们主要学习的是1&…...
SpringBoot中JSR303校验
JSR是 Java EE 的一种标准,用于基于注解的对象数据验证。在Spring Boot应用中,你可以通过添加注解直接在POJO类中声明验证规则。这样可以确保在使用这些对象进行操作之前,它们满足业务规则。个人认为非常有用的,因为它减少了代码中…...
图像数据增强方法概述
图像数据增强方法概述 1. 什么是图像数据增强技术?2. 图像数据增强技术分类2.1 几何变换Python 示例代码 2.2 颜色变换2.3 噪声添加 3. 参考文献 1. 什么是图像数据增强技术? 基础概念:图像增强技术是计算机视觉和图像处理领域中的一个关键技术,主要用…...
【学习笔记】无人机系统(UAS)的连接、识别和跟踪(五)-无人机跟踪
目录 引言 5.3 无人机跟踪 5.3.1 无人机跟踪模型 5.3.2 无人机位置报告流程 5.3.3 无人机存在监测流程 引言 3GPP TS 23.256 技术规范,主要定义了3GPP系统对无人机(UAV)的连接性、身份识别、跟踪及A2X(Aircraft-to-Everyth…...
分享从零开始学习网络设备配置--任务6.1 实现计算机的安全接入
项目描述 随着网络技术的发展和应用范围的不断扩大,网络已经成为人们日常生活中必不可少的一部分。园区网作为给终端用户提供网络接入和基础服务的应用环境,其存在的网络安全隐患不断显现出来,如非人为的或自然力造成的故障、事故;…...
双向链表(C语言版)
1. 双向链表的结构 注意:这里的“带头”跟单链表的“头结点”是两个概念,实际上在单链表阶段称呼不太严谨,但是为了更好地理解就直接称为单链表的头结点。带头链表里的头结点,实际为“哨兵位”,哨兵位结点不存储任何有…...
【算法/学习】前缀和差分
前缀和&&差分目录 1. 前缀和的概念及作用 🌈概念 🌈用途 🌙一维前缀和 🌙二维前缀和 2. 差分的概念及用途 🌈概念: 🌈用途 🌙一维差分 🌙二维差分 1. …...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
