02 网络编程-UDP用户数据包协议

news2024/11/24 21:01:03

目录

一、UDP简介

二、UDP协议的通信流程

三、UDP相关API接口

(1)创建套接字-socket()

(2)地址信息结构体sockaddr_in{}

(3)地址转换接口

(4)发送消息sendto()

(5)绑定地址bind()

(6)接收消息recvfrom()

四、UDP单向通信案例

(1)发送方

(2)接收方


一、UDP简介

        UDP全称“用户数据报协议”(User Datagram Protocol),即报文。是面向无连接的协议。是不可靠协议,不可靠指的是无法可靠的得知对方是否收到数据。

UDP的特征:

  • 无连接:通信双方不需要事先连接
  • 无确认:收到数据不给对方发回执确认
  • 不保证有序、丢失不重发
  • 采用帧同步的数据报通信方式(即通信双方每次的收发数据量相等)

        UDP类似于寄信,UDP的特点是无需连接、无需确认、无需缓冲区、无需分包序列号。因此UDP的效率比较高。

UDP的使用场景:广播、组播模式

二、UDP协议的通信流程

1、发送方(客户端)

(1)创建UDP套接字 int fd=socket();

(2)准备好接收方的地址 struct sockaddr_in peerAddr;

(3)给对方发送UDP数据报 sendto(fd,peerAddr)

(4)接收对方得消息 recvfrom(fd,peerAddr)

2、接收方(服务器)

(1)创建UDP套接字 int fd=socket();

(2)准备好自己的地址 struct sockaddr_in addr;

(3)绑定套接字地址 bind(fd,addr);

(4)坐等各方发来UDP数据报 recvfrom(fd,buf,buf_len,addr,addr_len); (

5)发送消息 sendto(fd,buf,buf_len,addr,addr_len);

        UDP协议需要先接收recvfrom之后才能发送sendto。是没有面向连接的协议。 UDP很少用于C/S(服务器/客户端)模型,显得服务器很被动,除非模拟TCP面向连接的流程。

三、UDP相关API接口

(1)创建套接字-socket()

1、创建套接字,申请一个应用于网络通信的接口
//头文件
         #include <sys/types.h> #include <sys/socket.h>
//函数原型
        int socket(int domain,int type,int protocol);
//参数
        @domain:选择需要的协议簇(网络协议) --域 AF_UNIX,AF_LOCAL 本地通信协议(UNIX本地域AF_LOCAL) AF_INET IPv4 AF_INET6 IPv6
        @type:协议类型 SOCK_STREAM 流式套接字TCP SOCK_DGRAM 数据报套接字UDP         @protocol:传输层协议的支持,如UDP协议IPPROTO_UDP、TCP协议IPPROTO_TCP等, 只要type正确即可,默认为0
//返回值
        成功 返回大于0的套接字文件描述符
        失败 返回-1

//备注

  • 常用的网络协议
    • AF_UNIX,AF_LOCAL:本地通信协议
    • AF_INET:IPv4地址协议
    • AF_INET6 :IPv6地址协议
  • 常用的协议类型
    • (1)流式套接字(TCP)————SOCK_STREAM
    • (2)数据报套接字(UDP)———— SOCK_DGRAM
  • 协议的支持 一般情况下某一个type会有一个特定的协议来支持它
  • 因此一般情况下只要确保type是正确的,该参数可以默认为0

(2)地址信息结构体sockaddr_in{}

struct sockaddr_in{ 
    sa_family_t sin_family; //选定地址协议:AF_INET 
    in_port_t sin_port; //端口号:明确哪一个进程处理该数据 
    struct in_addr sin_addr; //地址结构体internet address 
}; 

/*Internet address*/ 
struct in_addr{
     uint32_t s_addr;
     //32位整型的地址信息
}

(3)地址转换接口

如何把点分十进制的字符串转换为32位的无符号整型 “192.168.172.135”---->uint2_t 
//头文件 
    #include <sys/socket.h> 
    #include <netinet/in.h> 
    #include <arpa/inet.h> 

//函数原型 
    in_addr_t inet_addr(const cahr *cp); 

//把字符串ip转换为in_addr_t 
#include <arpa/inet.h> 
(1)主机地址转换为网络地址: 
    uint32_t htonl(uint32_t hostlong); 
    uint16_t htons(uint32_t hostshort); 

(2)网络地址转换为主机地址: 
    uint32_t ntonl(uint32_t netlong); 
    uint16_t ntons(uint32_t netshort);

(4)发送消息sendto()

对于UDP而言,由于没有连接,因此每次发送数据都必须携带对端的地址,就像写信,不管信封里面的内容长短,也不管是第几次寄信,每次寄信都必须写清楚对方的地址方可寄出。

//头文件
    #include <sys/types.h> 
    #include <sys/socket.h> 
//函数原型 
    ssize_t sendto(int sockfd,const void *buf,size_t len,int flags, const struct sockaddr *dest_addr,socklen_t addrlen);
//参数 
    @sockfd:通信套接字 
    @buf:需要发送的消息的首地址 
    @len:具体要发送的消息的长度(字节) 
    @flags:发送时的特殊标记,比如带外数据MSG_OOB,一般设置为0即可, 
    @dest_addr:目标地址,包括IP地址和端口号
    @addrlen:目标地址长度 
//返回值
     成功 返回已发送的数据的字节数 
     失败 返回-1

(5)绑定地址bind()

对于服务端来说,由于其IP和端口必须固定(否则客户端无法找到),因此服务端一般都需要将套接字绑定到某个IP和端口上,IP和端口一般统称网络地址或地址。当然,有些特定的场合客户端的套接字也可以绑定地址。

//头文件
    #include <sys/types.h>
    #include <sys/socket.h>

//函数原型
    int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen);

//参数
    @sockfd:套接字文件描述符
    @addr:具体的地址信息(IP地址于端口号、需要转换成标准地址结构体)
    @addrlen:地址信息的长度

//返回值
    成功 返回0
    失败 返回-1

(6)接收消息recvfrom()

ssize_t recvfrom( 
    int sockfd, //套接字文件描述符 
    void *buf, //接收数据缓冲区 
    size_t len, //接收数据缓冲区大小 
    int flags, //接收标记,比如MSG_OOB,一般设置为0 
    struct sockaddr *src_addr, //源端地址,不保存源端地址时可设置为NULL 
    socklen_t *addrlen //源端地址长度,不保存源端地址时可以设置为NULL 
); 

//参数 
    @sockfd:套接字 
    @buf:接收到的消息的用户缓冲区 
    @len:缓冲区的最大长度,避免越界 
    @flags:特殊选项,一般设置为0 
    @src_addr:消息来自哪里(用于存储对方的地址结构体) 
    @addrlen:明确上一个参数中的地址尺寸以及用于记录实际收到的对方地址尺寸 

//返回值 
    成功 返回实际收到的字节数 
    失败 返回-1 

        服务器只能让其他人知道自己的网络信息,但是服务器不知道其他人的网络信息 所以需要自己先调用recvfrom()去接收别人的消息才能保存其他人的网络信息

四、UDP单向通信案例

(1)发送方

/*发送端(客户端)*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h> /* superset of previous */

int main(int argc, char const *argv[])
{

    // 1. 创建一个udp套接字
    int socketfd = socket(AF_INET,    // 选择使用IPV4地址协议
                          SOCK_DGRAM, // 选择使用UDP 数据报套接字
                          0);         // 传输协议0 表示自动根据SOCK_DGRAM 匹配
    if (socketfd < 0)
    {
        perror("socket error");
        exit(0);
    }

    // 2. 设置好接收方的地址信息
    struct sockaddr_in toAddr = {
        .sin_family = AF_INET,                          // 设置为IPV4地址协议
        .sin_port = htons(60000),                       // 使用htons把本地字节序的端口号6000转换成网络字节序
        .sin_addr.s_addr = inet_addr("192.168.172.122") // 把点分十进制的字符串IP地址转换为32位的网络地址
    };

    char SendMsg[128] = {0};
    while (1)
    {
        // 清空发送消息缓冲区
        bzero(SendMsg, sizeof(SendMsg));

        // 3. 从键盘中获取消息
        fgets(SendMsg, 128, stdin);

        // 4. 发送消息
        ssize_t ret_val = sendto(socketfd,                   // 通信套接字
                                 SendMsg,                    // 需要发送的消息内容地址
                                 strlen(SendMsg),            // 具体发送的消息长度
                                 0,                          // 特殊选项 0 表示默认
                                 (struct sockaddr *)&toAddr, // 目标地址(接收者地址)
                                 sizeof(toAddr));            // 地址大小
    }

    return 0;
}

(2)接收方

/*接收端(服务器)*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h> /* superset of previous */

int main(int argc, char const *argv[])
{

    // 1. 创建一个udp套接字
    int socketfd = socket(AF_INET,    // 选择使用IPV4地址协议
                          SOCK_DGRAM, // 选择使用UDP 数据报套接字
                          0);         // 传输协议0 表示自动根据SOCK_DGRAM 匹配
    if (socketfd < 0)
    {
        perror("socket error");
        exit(0);
    }

    // 2. 设置好自己的地址信息
    struct sockaddr_in MyAddr = {
        .sin_family = AF_INET,                          // 设置为IPV4地址协议
        .sin_port = htons(60000),                       // 使用htons把本地字节序的端口号6000转换成网络字节序
        .sin_addr.s_addr = inet_addr("192.168.172.135") // 把点分十进制的字符串IP地址转换为32位的网络地址
    };

    // 3. 绑定地址
    if (bind(socketfd, (struct sockaddr *)&MyAddr, sizeof(MyAddr)))
    {
        perror("bind error");
        exit(0);
    }

    char RecvMsg[128] = {0};
    while (1)
    {
        bzero(RecvMsg, sizeof(RecvMsg));

        // 接收消息
        ssize_t ret_val = recvfrom(socketfd, RecvMsg, sizeof(RecvMsg), 0,
                                   NULL, NULL);
        if (ret_val > 0)
        {
            printf("成功收到%ld字节数据:%s\n", ret_val, RecvMsg);
        }
    }

    return 0;
}

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

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

相关文章

谁偷偷看了你的网站?这两款统计工具告诉你!小白易上手~

前两天&#xff0c;上线了一个知识库网站&#xff1a;花了一天时间&#xff0c;搭了个专属知识库&#xff0c;终于上线了&#xff0c;手把手教&#xff0c;不信你学不会。 想知道这个网站的流量如何&#xff0c;怎么搞&#xff1f; 网站流量统计分析工具&#xff0c;了解下&a…

EmguCV学习笔记 C# 2.2 Matrix类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV学习笔记目录 Vb.net EmguCV学习笔记目录 C# 笔者的博客网址&#xff1a;VB.Net-CSDN博客 教程相关说明以及如何获得pdf教…

全面解析Gerapy分布式部署:从环境搭建到定时任务,避开Crawlab的坑

Gerapy分布式部署 搭建远程服务器的环境 装好带docker服务的系统 Docker:容器可生成镜像&#xff0c;也可拉去镜像生成容器 示例&#xff1a;将一个环境打包上传到云端(远程服务器)&#xff0c;其他8个服务器需要这个环境直接向云端拉取镜像生成容器,进而使用该环境,比如有MYS…

ElasticSearch读写性能调优

文章目录 ES写入数据过程ES读取数据的过程写数据底层原理提升集群读取性能数据建模优化分片 提升写入性能的方法服务器端优化写入性能建模时的优化降低Translog写磁盘的频率&#xff0c;但是会降低容灾能力分片设定调整Bulk 线程池和队列 ES写入数据过程 客户端选择一个node发…

Linux系统编程:进程间通信 1:管道

1.进程间的互相通信的方式 进程间互相通信的方式共有7种&#xff1a; &#xff08;1&#xff09;无名管道&#xff08;同主机&#xff09; &#xff08;2&#xff09;有名管道&#xff08;同主机&#xff09; &#xff08;3&#xff09;信号&#xff08;同主机&#xff09;…

大语言模型(LLM)构建产品的一年经验总结【干货长文】

这是一份涵盖战术、运营和战略方面的大语言模型产品成功建设的实用指南。 现在是构建大型语言模型&#xff08;LLM&#xff09;的激动人心的时刻。在过去的一年里&#xff0c;LLM已经变得足够好&#xff0c;可以用于实际应用。而且它们每年都在变得更好更便宜。伴随着社交媒体上…

成功转行软件测试工程师,年薪30W+,经验总结都在这!

这是给转行做软件测试的小白的参考&#xff0c;无论是从零开始&#xff0c;或者是转行的朋友来说&#xff0c;这都是值得一看的&#xff0c;也是可以作为一种借鉴吧。 而且我决定转行IT&#xff08;互联网&#xff09;行业&#xff0c;其实理由也很简单&#xff0c;不用动体力…

全网爆火的从零到一落地接口自动化测试

前段时间写了一系列自动化测试相关的文章&#xff0c;当然更多的是方法和解决问题的思路角度去阐述我的一些观点。结合我自己实践自动化测试的一些经验以及个人理解&#xff0c;这篇文章来聊聊新手如何从零到一落地实践接口自动化测试。 为什么要做接口测试 测试理念的演变 早…

awesome-react-native 收集最好的React Native库,工具,教程,文章(上篇)

image 分类 分类 会议 连锁反应 - 波特兰&#xff0c;或者美国React Native EU - 弗罗茨瓦夫&#xff0c;波兰React Alicante - 西班牙阿利坎特ReactNext - 以色列特拉维夫React Berlin - 柏林&#xff0c;德国 用品 参考HOWTO文档什持续集成内幕 组件 UI 导航 导航/路由文章…

Aerospike学习笔记

1 概述 Aerospike 是一个分布式、可扩展的数据库。该架构具有三个关键目标&#xff1a; 为网络规模的应用程序创建灵活、可扩展的平台。提供传统数据库所期望的稳健性和可靠性&#xff08;如 ACID&#xff09;。以最少的人工参与提供运营效率。 文档链接&#xff1a;https://d…

【Linux —— 理解pthread库和底层逻辑】

Linux —— 理解pthread库和pthread_t 理解pthread库pthread库是一个动态库底层逻辑 LWPpthread_tpthread_t的概念pthread_t 的实现pthread_t 与 LWP 的关系 独立的栈空间管理 理解pthread库 pthread库是一个动态库 使用下面指令可以查找的系统目录下的库信息 ls /lib/x86_6…

海康VisionMaster使用学习笔记2-相机取图及参数设置

相机取图及参数设置 1. 关联相机-相机管理界面 除了以上两类外,第三方相机都可以通过全局相机进行连接 2. 相机参数设置 相机连接 跨网段IP,枚举 图像缓存数量 实时取流,断线重连 只有支持组播的相机才可以实时取流 触发设置 触发源 LINE0 可以保护电路 LINE2 可配置输入输出…

笔记(day21) 多线程以及锁的概念(超级完整版)

一、 多线程 1.1 程序,进程,线程 程序:一堆命令的集合,完成某个特定任务,是静态的,保存在硬盘中 进程:是程序的一次执行过程,就是把程序载入内存中执行,就是进程,是动态的 线程:是进程进一步细化,是程序内部的一条执行分支 如果一个进程同一时间执行多个线程,就是支持多线程 我…

简单测试AOP五种增强执行时机

1. 目标方法类&#xff0c;spring代理bean Component public class Test {public void test(){System.out.println("test 目标方法");}public void testException(){throw new RuntimeException();} } 2. 配置类 Configuration ComponentScan EnableAspectJAutoPr…

查询满足连续任意30天的全量交易的多个商户

需求说明&#xff1a; 先说表结构把&#xff0c;就是一张订单表存了商户号和其他相关信息&#xff0c;现在要查询这个订单表中以商户为主体的连续交易&#xff0c;也就是每天产生至少一笔订单的商户才算连续&#xff0c;不知道看到的小伙伴有没有什么想法和头绪&#xff0c;在一…

【C++进阶】map与set的封装实践

文章目录 map和setmapmap的框架迭代器operator()operator--()operator()和operator!()operator*()operator->() insertbegin()end()operator[] ()map的所有代码&#xff1a; set的封装迭代器的封装总结 map和set 通过观察stl的底层我们可以看见&#xff0c;map和set是通过红…

ubuntu16.04安装ibus拼音 输入法

前言 开始尝试搜狗输入&#xff0c;发现问题很多&#xff0c;放弃。网上说ibus比较稳定&#xff0c;决定安装ibus输入法。 步骤 安装ibus&#xff0c;使用如下命令, 安装完重启系统&#xff0c;使ibus生效&#xff1b; sudo apt install ibus ibus-pinyin ibus-table ibus-…

maven项目删除pom文件的依赖仍存留在项目中的解决方案【已解决】

前言 使用了pagehelper和mybatisplus的分页插件&#xff0c;起冲突了&#xff0c;想着注释掉pagehelper然后刷新maven&#xff0c;发现一直存留 mlgbz的 试了好多方法&#xff0c;什么缓存乱七八糟的&#xff0c;我以为出bug了 解决

Fiddle抓手机app的包

前言 本次文章讲述的是&#xff0c;fiddle获取手机代理&#xff0c;从而获取手机app的http、https请求&#xff01; 一.下载安装汉化Fiddle 1.点击Fiddler官网下载链接&#xff1a;Download Fiddler Web Debugging Tool for Free by Telerik 2.直接运行&#xff0c;选择自己需…

CUDA C++ 编程指南学习

CUDA C 编程指南 (nvidia.com)https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html 2. 编程模型 2.1. 内核 CUDA C 扩展了 C&#xff0c;允许程序员定义 C 函数&#xff0c;称为内核&#xff0c;当被调用时&#xff0c;N 个不同的 CUDA 线程并行执行 N 次&am…