网络编程UDP—socket实现(C++)

news2024/12/26 10:09:05

网络编程UDP—socket实现

  • 前言
  • UDP客户端和服务端
  • UDP使用场景
  • UDP socket C++代码示例
    • 客户端发送数据示例:
    • 服务端接收数据示例:
  • 关键函数的介绍
    • bind 绑定-监听 函数
      • 为什么一般都是监听所有网络接口呢?
        • 为什么需要用inet_addr进行转换?
    • sendto 发送 函数
    • socket函数
    • sockaddr_in结构体

前言

  • UDP通信需要哪些必要信息

    • IP地址
      • 用于定位通讯双方
    • 端口号
      • 用于标识通信的具体应用或服务。
      • 传输层通信都需要端口号的。
  • 网络要求

    • 双方必须是可以进行ip通信的
      • UDP依赖IP协议栈(IPv4或IPv6)完成路由、传输
    • 双方需要用同一协议

UDP客户端和服务端

  • 客户端

  • 构造数据报:包含目标IP、目标端口、数据内容。

  • 发送数据报:使用套接字 sendto() 函数将数据发送到目标地址。

  • 等待响应(如果有):接收服务端返回的数据。

  • 服务端

  • 创建监听套接字:绑定到指定IP和端口。

  • 等待数据:通过 recvfrom() 函数接收数据。

  • 处理请求:解析数据内容并执行相应操作。

  • 返回响应:将结果数据发送回客户端。

UDP使用场景

UDP适用于以下需要高效传输但容忍数据丢失的场景:

  • 实时通信:
    • 视频通话、语音通话(如VoIP)。
  • 在线游戏:
    • 游戏中快速同步状态。
  • 流媒体传输:
    • 实时视频、音频传输。
  • 广播/组播:
    • 数据包同时发送给多个主机(如局域网中发现服务)。
  • 轻量级请求/响应:
    • DNS查询、简单的远程控制。

UDP socket C++代码示例

客户端发送数据示例:

#include <iostream>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <cstring>

int main() {
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
    if (sock_fd < 0) {
        perror("Socket creation failed");
        return -1;
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080); // 目标端口号
    server_addr.sin_addr.s_addr = inet_addr("192.168.1.1"); // 目标IP地址

    const char* message = "Hello, UDP!";
    sendto(sock_fd, message, strlen(message), 0, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 发送数据

    close(sock_fd);
    return 0;
}

服务端接收数据示例:

#include <iostream>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <cstring>

int main() {
    int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); // 创建UDP套接字
    if (sock_fd < 0) {
        perror("Socket creation failed");
        return -1;
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080); // 监听端口
    server_addr.sin_addr.s_addr = INADDR_ANY; // 监听所有网络接口

    if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        close(sock_fd);
        return -1;
    }

    char buffer[1024];
    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);
    int bytes_received = recvfrom(sock_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&client_addr, &addr_len); // 接收数据
    if (bytes_received > 0) {
        buffer[bytes_received] = '\0';
        std::cout << "Received message: " << buffer << std::endl;
    }

    close(sock_fd);
    return 0;
}

关键函数的介绍

bind 绑定-监听 函数

  • 功能:

    • bind 函数用于将套接字绑定到特定的IP地址和端口号,通常用于服务端监听套接字。
      • 服务器先运行监听特定的IP地址和端口号;然后客户端再
  • 函数声明:

    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    

参数说明:

  1. sockfd:
    • 套接字描述符,由 socket 函数返回。
  2. addr:
    • 指向 sockaddr 结构体,表示要绑定的地址和端口。
      • 通常使用 sockaddr_in,需强制转换为 sockaddr。
  3. addrlen:
    • addr 的长度(使用 sizeof(sockaddr_in))。

返回值:
成功:返回 0。
失败:返回 -1,并设置 errno。

示例:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);        // 绑定端口号
server_addr.sin_addr.s_addr = INADDR_ANY; // 绑定到所有可用IP地址

if (bind(sock_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
    perror("Bind failed");
    close(sock_fd);
}

为什么一般都是监听所有网络接口呢?

server_addr.sin_addr.s_addr = INADDR_ANY;  // 绑定到所有可用IP地址

这行代码中的 INADDR_ANY 是一个常用的常量,它代表了一个特殊的 IP 地址,即 0.0.0.0。当你将它设置为服务器套接字的地址时,表示该服务器将 监听所有网络接口。

  • 理解什么是网络接口?

    • 网络接口指计算机或设备上 每一个可以用于发送或接收数据的网络连接通道。
      • 可以先理解为网卡,但是网络接口还包括一些虚拟网卡、本地回环接口(127.0.0.1)、甚至 VPN接口等,总的就是软硬 网络通道。
  • 服务器为什么一般监听所有网络接口?

    • 因为理论上我们希望只要是服务器这个端口号接收的,不管是哪一个网络接口,都交给服务器应用程序处理;
    • 除非我们就只想让服务器处理从某个网络接口 接收的数据,才设置某一个网络接口的ip地址。例如:
      • 只想让服务器接受本地(同一台机器上的应用程序)发出的数据
        server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        
为什么需要用inet_addr进行转换?

因为实际是采用网络字节序进行传输的,而用字符串形式十进制格式(如 “192.168.1.1”)只是为了人类方便阅读,所以需要转为网络字节序。

  • inet_addr作用

    • 用于将一个点分十进制表示的 IPv4 地址(例如 “192.168.1.1”)转换为网络字节序的二进制格式。
  • inet_addr 将一个 IPv4 地址的点分十进制字符串(如 “192.168.1.1”)转换为网络字节序的 32 位整数。例如:

    • “192.168.1.1” 在十进制中是:192 * 256^3 + 168 * 256^2 + 1 * 256^1 + 1 * 256^0
    • 对应的二进制表示是:11000000 10101000 00000001 00000001
  • 值得注意的是,inet_addr 已经不推荐使用,特别是在现代网络编程中,因为它对无效地址的处理可能不够清晰(比如返回 -1 会被误认为是有效的地址)。推荐使用 inet_pton 函数来替代,它更加健壮和安全。inet_pton 允许支持不同的地址族(IPv4 和 IPv6),并且不会出现类似 inet_addr 那样的错误返回值。

sendto 发送 函数

  • 功能:

    • 用于通过UDP套接字发送数据报到指定地址和端口
  • 函数声明

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);

参数说明:

  1. sockfd:
    • 套接字描述符,由 socket 函数返回。
  2. buf:
    • 指向要发送的数据的缓冲区。
  3. len:
    • 要发送的数据长度(字节数)。
  4. flags:
    • 传输标志,通常设置为 0。
  5. dest_addr:
    • 指向一个 sockaddr 结构体,表示目标地址。
      • 通常传入 sockaddr_in,需要通过强制类型转换为 sockaddr。
  6. addrlen:
    • dest_addr 的长度(使用 sizeof(sockaddr_in))。
      返回值:
      成功:返回实际发送的字节数。
      失败:返回 -1,并设置 errno。

示例:

const char *message = "Hello, UDP!";
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
server_addr.sin_addr.s_addr = inet_addr("192.168.1.1");

sendto(sock_fd, message, strlen(message), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));

socket函数

  • 作用

    • 用于创建套接字socket,套接字是网络通信的基础,用于在客户端和服务端之间建立通信。
    • 确定协议族(IPv4还是)、TCP还是UDP
  • 函数声明

    int socket(int domain, int type, int protocol);
    

参数说明:

  1. domain:指定通信的协议族(地址类型)。
  • AF_INET:IPv4。
  • AF_INET6:IPv6。
  • AF_UNIX:本地通信(不使用网络)。
  1. type:指定套接字的类型。
  • SOCK_STREAM:TCP(面向连接,保证数据可靠性)。
  • SOCK_DGRAM:UDP(无连接,适合快速传输)。
  1. protocol:通常指定为 0,表示使用默认协议。
  • 如果 type 是 SOCK_DGRAM,默认使用 UDP 协议。
  • 如果 type 是 SOCK_STREAM,默认使用 TCP 协议。

返回值:
成功:返回套接字描述符(非负整数)。
失败:返回 -1,并设置 errno。

示例:

int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (sock_fd < 0) {
    perror("Socket creation failed");
}

sockaddr_in结构体

  • 功能

    • 用于表示 IPv4 地址和端口信息,通常在网络通信中用于绑定或指定目标地址。
  • 定义:

struct sockaddr_in {
    short sin_family;        // 地址族(必须为 AF_INET)
    unsigned short sin_port; // 端口号(网络字节序,需要使用 htons() 转换)
    struct in_addr sin_addr; // IPv4 地址
    char sin_zero[8];        // 填充字节,保持与 struct sockaddr 的大小一致(不使用,置 0)
};

字段说明:

  1. sin_family:
    • 必须设置为 AF_INET(IPv4协议)。
  2. sin_port:
    • 16位端口号,必须用 htons() 将主机字节序转换为网络字节序。
  3. sin_addr:
    • 一个 struct in_addr 结构体,表示IPv4地址。
      • 可以用 inet_addr() 或 inet_aton() 转换字符串形式的IP地址。
      • 也可以设置为 INADDR_ANY,表示绑定到本地所有可用IP。
  4. sin_zero:
    • 填充字段,不使用,应设置为 0。

示例:

struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;                // IPv4
server_addr.sin_port = htons(8080);              // 端口号(转换为网络字节序)
server_addr.sin_addr.s_addr = inet_addr("192.168.1.1"); // 目标IP地址
memset(server_addr.sin_zero, 0, sizeof(server_addr.sin_zero)); // 填充为0

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

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

相关文章

大模型讲师叶梓分享前沿论文:ChatDoctor——基于大模型的医疗聊天机器人

人工智能咨询培训老师叶梓 转载标明出处 人工智能讲师培训咨询老师叶梓分享前沿技术&#xff1a;基于大模型的医疗聊天机器人 大模型在医疗领域的应用仍相对有限&#xff0c;通用领域模型在提供医疗建议时常常出现错误。为了解决这一问题&#xff0c;Li等人提出了一个名为ChatD…

GitLab 停止中国区用户访问,为用户提供60天的迁移期

近日&#xff0c;全球知名的代码托管平台 GitLab 宣布了一个重大变化&#xff1a;将停止为中国大陆、香港及澳门地区的用户提供访问服务&#xff0c;建议用户访问授权国内的产品极狐 GitLab.cn。 极狐 GitLab.cn 是 GitLab 授权的独立中国公司&#xff0c;之前该公司还发生过举…

H3C MPLS跨域optionB

实验拓扑 实验需求 如图,VPN1 和 VPN2 分别通过运营商 MPLS VPN 连接各自分支机构按照图示配置 IP 地址,VPN1 和 VPN2 连接同一个 PE 设备的私网 IP 网段存在地址复用,使用多 VRF 技术来防止 IP 冲突AS 100 和 AS 200 内部的公共网络中各自运行 OSPF 使 AS 内各设备的 Loo…

Flink SQL Cookbook on Zeppelin 部署使用

简介&#xff1a;对于初学者来说&#xff0c;学习 Flink 可能不是一件容易的事情。看文档是一种学习&#xff0c;更重要的是实践起来。但对于一个初学者来说要把一个 Flink SQL 跑起来还真不容易&#xff0c;要搭各种环境&#xff0c;真心累。很幸运的是&#xff0c;Flink 生态…

6、mysql的MHA故障切换

MHA的含义 MHA&#xff1a;master high availability&#xff0c;建立在主从复制基础上的故障切换的软件系统。 主从复制的单点问题&#xff1a; 当主从复制当中&#xff0c;主服务器发生故障&#xff0c;会自动切换到一台从服务器&#xff0c;然后把从服务器升格成主&…

基于单片机的智能递口罩机器人设计

本设计是一款智能递口罩机器人&#xff0c;主控器采用STM32单片机&#xff0c;ESP32协同控制&#xff0c;在支持MicroPython的OpenMV机器视觉模块的控制下&#xff0c;实现人脸搜索与识别&#xff0c;进而控制小车的运动及机械臂递口罩动作。这款机器人拥有温湿度传感器&#x…

实训项目-人力资源管理系统-1Company子模块

目录 前言&#xff1a; 用例图设计&#xff1a; 系统设计 开发方式&#xff1a; 技术架构 系统结构&#xff1a; API文档&#xff1a; 工程搭建&#xff1a; 搭建父项目 pom&#xff1a; 创建公共子模块&#xff1a; 返回实体&#xff1a; 分布式id生成器&#xff1a; …

前端bug调试

报错和Bug&#xff0c;是贯穿程序员整个编程生涯中&#xff0c;无法回避的问题。而调试&#xff0c;就是帮助程序员定位问题、解决问题的重要手段&#xff0c;因此&#xff0c;调试是每个程序员必备技能。 调试基本流程 核心原则&#xff1a;最重要的就是不断地缩小范围&…

【落羽的落羽 C语言篇】自定义类型——联合体、枚举

文章目录 一、联合体1. 联合体类型的声明2. 联合体的特点3. 联合体的大小4. 联合体和结构体的对比 二、枚举1. 枚举类型的声明2. 枚举类型的优点 一、联合体 1. 联合体类型的声明 联合体像结构体一样&#xff0c;也是由一个或多个成员构成&#xff0c;这些成员可以是不同的类…

大数据技术-Hadoop(二)HDFS的介绍与使用

目录 1、HDFS简介 1.1 什么是HDFS 1.2 HDFS的优点 1.3、HDFS的架构 1.3.1、 NameNode 1.3.2、 NameNode的职责 1.3.3、DataNode 1.3.4、 DataNode的职责 1.3.5、Secondary NameNode 1.3.6、Secondary NameNode的职责 2、HDFS的工作原理 2.1、文件存储 2.2 、数据写…

学习threejs,THREE.CircleGeometry 二维平面圆形几何体

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.CircleGeometry 圆形…

替换 Docker.io 的 Harbor 安全部署指南:域名与 IP 双支持的镜像管理解决方案

经过验证 替换 Docker.io 的方式失败了, 以下的过程中还是需要设置 registry-mirrors 才行 以下是一篇详细教程&#xff0c;展示如何基于 openssl.conf 配置生成域名为 registry-1.docker.io 和 IP 地址为 172.16.20.20 的证书&#xff0c;构建 Harbor 服务。 环境准备 系统环境…

【源码编译】windows下mingw64安装以及cmake调用

最近因为安装MIRTK库&#xff0c;太多第三方依赖了&#xff0c;太折磨了&#xff0c;学习了使用Cmake&#xff0c;有些库又需要Fortran编译器&#xff0c;VS2022里面装了但又调用不了&#xff0c;也不知道为什么&#xff0c;最后装的mingw64&#xff0c;记录一下。 1、mingw64安…

【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111

文章目录 一、算法概念111二、算法原理&#xff08;一&#xff09;感知机&#xff08;二&#xff09;多层感知机1、隐藏层2、激活函数sigma函数tanh函数ReLU函数 3、反向传播算法 三、算法优缺点&#xff08;一&#xff09;优点&#xff08;二&#xff09;缺点 四、MLP分类任务…

基于AI IDE 打造快速化的游戏LUA脚本的生成系统

前面写了一篇关于使用AI IDE进行C安全开发的博客《使用AI IDE 助力 C 高性能安全开发&#xff01;》&#xff0c; 得到许多同学们的喜欢&#xff0c;今天我们来继续在游戏开发中扩展一下AI的能力&#xff0c;看看能不能给游戏研发团队一些启发。 在游戏研发中&#xff0c;Lua曾…

系统思考VS过度管理

业绩没起来&#xff0c;领导者最容易做的就是抓管理。这样的“抓管理”真的有效吗&#xff1f;当业务还没起飞的时候&#xff0c;过度管理其实是一种伤害。就像一条呼啸而过的鞭子&#xff0c;看起来让团队更“整齐”&#xff0c;但实际上可能打散了协作的节奏。管理的本质是支…

IT运维的365天--021 服务器上的dns设置后不起作用

之前在内网搭建了一个和外网同域名的网站&#xff0c;开发同事今天告诉我&#xff0c;程序调试发现可能服务器不能正常访问自己内网的网站内容。于是&#xff0c;今天的故事开始了。 前面的文章在下面列出&#xff0c;当然不看也问题不大&#xff0c;今天的主题是&#xff1a;…

机器人C++开源库The Robotics Library (RL)使用手册(二)

由于RL库采用跨平台CMake源码,可以轻松在win、ubantu等平台部署、编译,win通常用VS编译器,为了便于使用、阅读,需要将CMake编译成VS工程。 1、准备三个工具:CMake、VS、QT 为了在Windows上编译RL和依赖项,您需要安装一个编译器(例如。,Visual Studio 2017)和跨平台构…

ShaderJoy ——一种可交互的翻页效果【GLSL】

效果视频 Shader 特效——可与鼠标交互的翻页效果 效果图 完整代码 #define pi 3.14159265359 #define radius .1#iChannel0 "file://./images/Woolly_3.png" #iChannel1 "file://./images/Woolly_4.png"void mainImage( out vec4 fragColor, in vec2 fra…

oracle怎样使用logmnr恢复误删除的数据

如果有同事误删除数据了&#xff0c;可以用logmnr挖掘归档日志&#xff0c;生成回滚sql&#xff0c;快速恢复数据&#xff0c;比用整个库的备份恢复要快得多。 一 操作步骤 1.1 创建目录 su - oracle mkdir logmnr create directory logmnr_dir as /home/oracle/logmnr; …