Linux网络:运用UDP实现网络通信(网络套接字的创建绑定)

news/2025/9/25 22:21:44/文章来源:https://www.cnblogs.com/wzzkaifa/p/19112187

文章目录

      • 1. UDP网络程序的服务端
        • 1.1 封装一个UdpServer类
        • 1.2 获取socket套接字
        • 1.3 绑定套接字

  • 序:在上一章中,先介绍网络基础,然后阐述以太网通信原理、局域网通信的数据封装分用及跨网络靠路由器通信,指出IP和Mac地址作用。接着聚焦网络套接字,说明端口号用于标识主机网络进程,而本章将从UDP协议的角度去理解网络通信的原理。

传输层提供的协议有TCP和UDP两种,提供数据收发的服务,TCP叫做传输控制协议,有链接(确保通信信道的可靠性,收发两端能正常交流),有可靠性(传输层),只有成功建立链接才能进行通信,面向字节流,UDP叫做用户数据报协议,无连接(不需要确保通信信道的可靠性,直接发),不可靠性,面向数据报(发出去的数据有明显的边界,意思就是要发数据就发完整的数据,要么就不发)
其中的udp的不可靠性,并不意味着就是不好了,这是一个中性词,不可靠意味着简单,方便,而要维持可靠性,就必然需要花费一定的成本和资源,所以可靠性的负担也是要被考虑到的地方,所以对于选择tcp还是udp进行通信,还是要因地制宜!!!

在这里插入图片描述

H代表主机,n表示网络,l表示long四字节,s表示short两字节
第一个是32位的,主机转网络序列。
第二个是16位的,主机转网络序列。
第三个是32位的,网络转主机序列。
第四个是16位的,网络转主机序列。

网络套接字

在这里插入图片描述

套接字编程的种类:

  1. 域间套接字编程—>同一个机器内
  2. 原始套接字编程—>网络工具(抓包… )
  3. 网络套接字编程—>用户间的网络通信

想将三个网络接口统一抽象化—>参数的类型必须是统一的

1. UDP网络程序的服务端

1.1 封装一个UdpServer类

要想启动服务端,服务端至少要一个构造,一个析构,一个初始化和一个运行的接口!!!

class UdpServer{
public:
UdpServer()
{}
void Init()
{}
void Run(func_t func)
{}
~UdpServer()
{}
private:
};
1.2 获取socket套接字

想要使用UDP套接字,就必须先获取一个套接字,要用到下面的一个函数来获取套接字

在这里插入图片描述

需要包含下面两个库
#include
#include
int socket(int domain,int type,int protocol);

该函数的第一个参数表示创建的套接字的域(IPv4还是IPv6,在udp场景中使用AF_INET或者PF_INET选项(IPv4)),不同场景要创建不同种类的套接字
在这里插入图片描述

第二个参数表示当前socket对应的类型,例如SOCK_STREM表示的就是流式套接字,SOCK_DGRAM表示用户数据报套接字,显然,之前提到的UDP是面向用户数据报的,TCP是面向字节流的,对于不同的场景填充不同的套接字类型,所以在UDP的场景下我们选择SOCK_DGRAM的套接字类型
在这里插入图片描述

第三个参数表示协议类型,当前默认不用考虑,直接填0

返回值RETURN_VALUE,如果成功了套接字被返回,失败了-1被返回,错误码被设置!这说明该返回值就是一个文件,所以打开一个套接字就是打开一个文件(一切皆文件),类比文件描述符,要想进行网络上的通信就必须经过“网络文件描述符”
在这里插入图片描述

class UdpServer{
public:
void Init()
{
//1.创建udp socket
_sockfd=socket(AF_INET,SOCK_DGRAM,0);
//用的网络协议IPv4,SOCK_DGRAM数据报(无连接,不稳定)
//因为#define AF_INET PF_INET,所以用PF_INET也是一样的
if(_sockfd < 0)
{
//使用日志系统对错误信息进行打印
log(Fatal,"socket create error, _sockfd: %d", _sockfd);
exit(SOCKET_ERR);
}
log(Info,"socket create success, _sockfd: %d", _sockfd);
}
private:
//添加私有成员
int _sockfd; //网络文件描述符
};
1.3 绑定套接字

绑定套接字要用到bind函数:
在这里插入图片描述

第一个参数:要绑定的套接字(sockfd)
第二个参数:一个结构体,该结构体是本文一开始讲到的通用接口,所有的套接字接口都是struct sockaddr,其参数传递的时候都是struct sockaddr * ,但是我们现在使用的是网络通信,所以我们使用的是struct sockaddr_in这样的结构,要传参数的时候直接强转就行了。
在这里插入图片描述
第三个参数:第二个参数的结构体的长度

在绑定的时候,必须要知道当前服务的端口号和IP地址,IP确定唯一的一台主机,端口号确定该主机上对应的一个服务

uint16_t defaultport = 5070;
std::string defaultip = "0.0.0.0";
class UdpServer{
public:
UdpServer(const uint16_t &port = defaultport,const std::string &ip = defaultip)
:_port(port)
,_ip(ip)
{}
private:
//添加私有成员
std::string _ip; //IP地址, 0.0.0.0 任意地址绑定
uint16_t _port;  //表示服务器进程的端口号
};

虽然bind的第二个参数要传的是struct sockaddr,但我们实际要用的是struct sockaddr_in,但是又由于网络接口统一抽象化,所以只需要将struct sockaddr_in填充完后再强转就行了。

#include //要使用该结构体所要包含的头文件
#include  //主机网络序列转换所需要用到的头文件

初始化struct sockaddr_in结构体
在这里插入图片描述

struct sockaddr_in结构体的各个参数介绍:
在这里插入图片描述

其中的sin_zero表示这个结构体的填充字段,没啥用,就是占位符。其中的sin,s表示socket,in表示inet。

在这里插入图片描述

sin_addr表示IP地址,但是,如果直接将服务器的IP地址传给sin_addr的话,是不行的,因为该参数还是一个结构体,这个结构体里面的in_addr_t才是能传递参数的网络序列,所以要想将IP地址传入进去,第一步就是要将string类型的IP地址转化为uint32_t的类型,第二步是将uint32_t转化为网络序列
在这里插入图片描述

问题一:如何将一个字符串的IP地址转化为一个整数?又怎么转换回来?

使用inet_addr函数,可以直接将字符串转化为4字节整数,并且转化为网络序列。

sin_port表示该服务器的端口号,该参数的类型是in_port_t,而该类型就是uint16_t,但是到这一步还是不可以直接将服务器的端口号传进去,需要注意的是,端口号需要保证是网络字节序列,因为端口号是要给对方发送的,所以还需要将主机序列转化为网络序列,使用函数htons
在这里插入图片描述

sin_family表示要表明自己的结构体所对应的类型,也就是套接字的域,因为我们使用的UDP的套接字的域是IPv4,所以这里直接把AF_INET传过去就行

问题二:但是我们并没有在struct sockaddr_in的里面看到famliy啊?

在这里插入图片描述

我们可以看到该结构体中有一个像这样的宏,传一个_sin进去。
在这里插入图片描述

**该宏定义是意思就是用sa_fanily_t sa_prefix##family代替前面__SOCKADDR_COMMON(sin_ ) **

问题三:其中的“##”是什么意思?

可以把位于它两边的符号合成一个符号,它允许宏定义从分离的文本片段创建标识符。 ## 被称为记号粘合

这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。
这里我们想想,写⼀个函数求2个数的较大值的时候,不同的数据类型就得写不同的函数。

比如

int int_max(int x, int y)
{
return x>y?x:y;
}
float float_max(float x, float y)
{
return x>yx:y;
}

但是这样写起来太繁琐了,现在我们这样写代码试试:

//宏定义
#define GENERIC_MAX(type)        \
type type##_max(type x, type y)  \
{                                \
return (x>y?x:y);            \
}

所以这块宏定义就是在sin_后面加了一个family变成了sin_family来表示该参数,这也就是sin_family的由来

class UdpServer{
public:
void Init()
{
//1.创建udp socket
//...
//2.绑定bind socket
//2.1 准备数据
struct sockaddr_in local;
//memset(&local,0,sizeof(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());
//1.string -> uint32_t 2. uint32_t必须是网络序列的
//如果IP要被网络使用,IP也必须是网络序列的
local.sin_addr.s_addr=INADDR_ANY;//(INADDR_ANY就是000000000全零)
//2.2 开始绑定
if(bind(_sockfd, (const struct sockaddr*)&local, sizeof(local)) < 0)
{
log(Fatal,"bind error,errno: %d ,strerror: %s",
errno, strerror(errno));
exit(BIND_ERR);
}
log(Info,"bind success, _sockfd: %d",_sockfd);
}
private:
int _sockfd; //网络文件描述符
std::string _ip; //IP地址, 0.0.0.0 任意地址绑定
uint16_t _port;  //表示服务器进程的端口号
};

总结:

本文主要介绍了传输层的TCP与UDP协议特点:TCP可靠、面向连接、字节流;UDP不可靠、无连接、面向数据报。重点讲解UDP服务端编程:创建socket(AF_INET/SOCK_DGRAM)、绑定IP和端口(使用struct sockaddr_in,调用bind),涉及htons、inet_addr等网络字节序转换,强调代码封装与关键步骤实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/917614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常见进制

D:/study/C语言 devc/test9.c

9.25总结

今天是9.25,今天是星期四,今天上午上了一节数据结构和一节跆拳道课,跆拳道课上学了好多动作,还教我们劈叉,锻炼我们的韧带。下午就没有课程安排了,中午和朋友打了一会儿游戏,然后睡了一觉,醒来之后,去教室学了…

做受视频播放网站wordpress实现文章连载目录

感情是偏执的 越爱越是偏执的 不相信我看到的 硬要说裂缝不过 是皱褶 怎么先炽热的却先变冷了 慢热的却停不了还在沸腾着 看时光任性快跑随意就转折 慢冷的人啊 会自我折磨 冲动的人向来听不见挽留 这世界大得让你很难不旅游 浪漫让你温柔 也让你最惹人 泪流 …

proxifier联合burpsuite抓包小程序,但是小程序连不上网解决办法(亲测)

找了网上好多教程都没找到对应我这种情况的解决方法,我这个方法希望能帮到跟我情况一样的同学问题描述 之前看小迪的课程的时候学到过burpsuite加proxifier联合抓小程序的包,当时也复现成功了,后面在看到小程序资产…

完整教程:C语言——函数(超详细分析)

完整教程:C语言——函数(超详细分析)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mo…

大 LCP 时代(stupid.*)

大 LCP 时代(stupid.*) 题目描述 LCP 就是传说中的最长公共前缀,至于为什么要加上一个大字,那是因为…你会知道的(有大病)。 首先,求LCP就要有字符串。既然那么需要它们,那就给出n个字符串好了。 于是你需要回答…

网站中的滑动栏怎么做的四川建设网网

虚拟技术十分热门.虚拟技术是将一台物理硬件计算机虚拟成多台软件计算机.每一台虚拟出来的软件计算机(以下叫做虚拟机)用起来都就象是在用那台被虚拟的硬件计算机(以下叫做真实机)完全一样.当然这样的说法忽略了虚拟机相对于真实机在执行效益上不可避免所存在的损失.所以如何减…

实用指南:Python实现手榴弹爆炸算法(Grenade Explosion Method, GEM)(附完整代码)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Day08-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\David\array-ArrayDemo01~07

数组首先要声明数组变量才能使用如dataType[] arrayRefVar; java语言中使用new操作来创建数组,如dataType[ ] arrayRefVar = new dataType[arraysize] 数组通过索引访问,索引从0开始内存分析堆:存放new的对象和数组…

yolov10_float16.tflite TO yolov10_int8.tflite

使用google colab平台1. 安装ultralytics!pip install ultralytics2. 导入yolo并从ultralytics加载yolov10n.ptfrom ultralytics import YOLO model = YOLO("https://github.com/ultralytics/assets/releases/dow…

ansible注意的和错误代码分析

一、需要注意的点分清楚这个是主控节点还是被控节点的操作,有的时候是一个文件从主控到被控节点,还是被控节点的文件到主控节点上面了剧本执行报错代码 # 仔细看,报错的原因就是ansibel_lvm 未定义,写错了变量名TA…

用 Rust 和 Tesseract OCR 识别验证码

一、背景介绍 Rust 是一种系统级编程语言,以性能和安全性著称。在自动化测试和数据分析场景中,验证码识别是一个常见挑战。结合 Tesseract OCR,我们可以使用 Rust 构建一个高效的验证码识别工具。本文将介绍如何使用…

基于寄存器地址amp;标准外设库的LED流水灯

实验任务2 1.1先在工程总文件夹中创建User,Library和Startup三个文件夹,然后右键keil中的文件夹Source Group 1添加工程所需的这三个文件夹。1.2分别在Library,Startup和User三个文件夹中添加必要的头文件和.c文件。…

用 Swift 和 Tesseract OCR 实现验证码识别

一、背景介绍 Swift 是 Apple 推出的现代化编程语言,广泛应用于 iOS 和 macOS 应用开发。结合 Tesseract OCR,可以在移动和桌面应用中高效地识别验证码。本文将展示如何使用 Swift 结合 Tesseract OCR 实现验证码自动…

Rust 和 Tesseract OCR 实现验证码识别

一、背景介绍 Rust 以其高性能和内存安全著称,适合构建高效的图像处理和 OCR 应用程序。本文将结合 Tesseract OCR,使用 Rust 实现验证码识别。 二、环境准备 2.1 安装 Rust 更多内容访问ttocr.com或联系1436423940 …

AI-Powered-ToDo-List

AI-Powered-ToDo-List https://github.com/fanqingsong/AI-Powered-ToDo-ListAI 智能任务管理器基于 LangGraph 和 React 的智能任务管理应用,支持传统手动管理和 AI 对话式管理两种方式。✨ 功能特性🎯 双重管理方…

Netty:完成RPC服务(实战)

Netty:完成RPC服务(实战)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco",…

Python 在 Web 开发中的应用与趋势

一、引言 🌐 随着互联网的普及和应用场景的不断拓展,Web 开发已经成为软件工程的核心组成部分。从简单的静态网页到复杂的交互式应用,Web 技术在近二十年间经历了飞速发展。而 Python,作为一门简洁优雅、功能强大…

网页设计怎么建站点店铺管理软件

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;MQ ⛺️稳中求进&#xff0c;晒太阳 定义 消息队列&#xff1a;一般我们简称为MQ(Message Queue) Message Queue :消息队列中间件&#xff0c;很多初学者认为&#xff0c;MQ通过消息的发送…

校园交友|基于SprinBoot+vue的校园交友网站(源码+数据库+文档) - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …