UDP编程详解[通俗易懂]

UDP编程详解[通俗易懂]UDP与TCP的不同之处是:他的通信不需要建立连接的过程。中文名称用户数据报协议。时OSI参考模型中一种无连接的传输层协议。提供面向事务的简单不可靠信息传送服务,UDP在IP报文中的协议号是17.与T

大家好,又见面了,我是你们的朋友全栈君。


UDP与TCP的不同之处是:他的通信不需要建立连接的过程。中文名称用户数据报协议。时OSI参考模型中一种无连接的传输层协议。提供面向事务的简单不可靠信息传送服务,UDP在IP报文中的协议号是17.与TCP(传输控制协议)一样,UDP协议直接位于IP(网际协议)协议的顶层,根据TCP/IP参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将数据压缩成数据包的形式,一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。

报文格式

源端口(2字节)+目的端口(2字节)+长度(2字节)+校验和(2字节)+数据
DJmkGT.png

通信过程

UDP协议较TCP简单很多,减少了TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议。UDP客户端在发送数据时并不判断主机是否可达,服务器是否开启等问题,他不能确定数据是否成功到达服务器,他只是将数据简单的封了一个包,之后就丢出去了。

UDP客户端流程

  1. 创建socket:socket()
  2. 通信:sendto() & recvfrom()
  3. 关闭socket:closesocket()

UDP客户端编码

void udpclient(int argc, char **argv)
{
    int sock, port, count;
    struct hostent *host;
    struct sockaddr_in server_addr;
    const char *url;

    if (argc < 3)
    {
        rt_kprintf("Usage: udpclient URL PORT [COUNT = 10]\n");
        rt_kprintf("Like: tcpclient 192.168.12.44 5000\n");
        return ;
    }

    url = argv[1];
    port = strtoul(argv[2], 0, 10);

    if (argc > 3)
        count = strtoul(argv[3], 0, 10);
    else
        count = 10;

    /* 通过函数入口参数url获得host地址(如果是域名,会做域名解析) */
    host = (struct hostent *) gethostbyname(url);

    /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        rt_kprintf("Socket error\n");
        return;
    }

    /* 初始化预连接的服务端地址 */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));

    /* 总计发送count次数据 */
    while (count)
    {
        /* 发送数据到服务远端 */
        sendto(sock, send_data, strlen(send_data), 0,
               (struct sockaddr *)&server_addr, sizeof(struct sockaddr));

        /* 线程休眠一段时间 */
        rt_thread_delay(50);

        /* 计数值减一 */
        count --;
    }

    /* 关闭这个socket */
    closesocket(sock);
}

UDP服务器流程

  1. 创建socket:socket()
  2. 将创建的socket绑定到一个IP地址和端口号上:bind()
  3. 等待接收数据报,处理完成后将结果返回到客户端:recvfrom() & sendto(). recvfrom()会阻塞住等待接收消息
  4. 关闭socket:close()

UDP服务器编码

static void udpserv(int argc, char **argv)
{
    int sock;
    int bytes_read;
    char *recv_data;
    socklen_t addr_len;
    struct sockaddr_in server_addr, client_addr;

    /* 分配接收用的数据缓冲 */
    recv_data = rt_malloc(BUFSZ);
    if (recv_data == RT_NULL)
    {
        /* 分配内存失败,返回 */
        rt_kprintf("No memory\n");
        return;
    }

    /* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        rt_kprintf("Socket error\n");

        /* 释放接收用的数据缓冲 */
        rt_free(recv_data);
        return;
    }

    /* 初始化服务端地址 */
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(5000);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));

    /* 绑定socket到服务端地址 */
    if (bind(sock, (struct sockaddr *)&server_addr,
             sizeof(struct sockaddr)) == -1)
    {
        /* 绑定地址失败 */
        rt_kprintf("Bind error\n");

        /* 释放接收用的数据缓冲 */
        rt_free(recv_data);
        return;
    }

    addr_len = sizeof(struct sockaddr);
    rt_kprintf("UDPServer Waiting for client on port 5000...\n");

    while (1)
    {
        /* 从sock中收取最大BUFSZ - 1字节数据 */
        bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
                              (struct sockaddr *)&client_addr, &addr_len);
        /* UDP不同于TCP,它基本不会出现收取的数据失败的情况,除非设置了超时等待 */

        recv_data[bytes_read] = '
static void udpserv(int argc, char **argv)
{
int sock;
int bytes_read;
char *recv_data;
socklen_t addr_len;
struct sockaddr_in server_addr, client_addr;
/* 分配接收用的数据缓冲 */
recv_data = rt_malloc(BUFSZ);
if (recv_data == RT_NULL)
{
/* 分配内存失败,返回 */
rt_kprintf("No memory\n");
return;
}
/* 创建一个socket,类型是SOCK_DGRAM,UDP类型 */
if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
rt_kprintf("Socket error\n");
/* 释放接收用的数据缓冲 */
rt_free(recv_data);
return;
}
/* 初始化服务端地址 */
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5000);
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
/* 绑定socket到服务端地址 */
if (bind(sock, (struct sockaddr *)&server_addr,
sizeof(struct sockaddr)) == -1)
{
/* 绑定地址失败 */
rt_kprintf("Bind error\n");
/* 释放接收用的数据缓冲 */
rt_free(recv_data);
return;
}
addr_len = sizeof(struct sockaddr);
rt_kprintf("UDPServer Waiting for client on port 5000...\n");
while (1)
{
/* 从sock中收取最大BUFSZ - 1字节数据 */
bytes_read = recvfrom(sock, recv_data, BUFSZ - 1, 0,
(struct sockaddr *)&client_addr, &addr_len);
/* UDP不同于TCP,它基本不会出现收取的数据失败的情况,除非设置了超时等待 */
recv_data[bytes_read] = '\0'; /* 把末端清零 */
/* 输出接收的数据 */
rt_kprintf("\n(%s , %d) said : ", inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
rt_kprintf("%s", recv_data);
/* 如果接收数据是exit,退出 */
if (strcmp(recv_data, "exit") == 0)
{
closesocket(sock);
/* 释放接收用的数据缓冲 */
rt_free(recv_data);
break;
}
}
return;
}
'; /* 把末端清零 */ /* 输出接收的数据 */ rt_kprintf("\n(%s , %d) said : ", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); rt_kprintf("%s", recv_data); /* 如果接收数据是exit,退出 */ if (strcmp(recv_data, "exit") == 0) { closesocket(sock); /* 释放接收用的数据缓冲 */ rt_free(recv_data); break; } } return; }

参考文献

  1. RT-Thread视频中心内核入门
  2. RT-Thread文档中心

本文作者: CrazyCatJack

本文链接: https://www.cnblogs.com/CrazyCatJack/p/14408893.html

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

关注博主:如果您觉得该文章对您有帮助,可以点击文章右下角推荐一下,您的支持将成为我最大的动力!


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/155103.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 决策树—回归[通俗易懂]

    决策树—回归[通俗易懂]核心:划分点选择+输出值确定。一、概述决策树是一种基本的分类与回归方法,本文叙述的是回归部分。回归决策树主要指CART(classificationandregressiontree)算法,内部结点特征的取值为“是”和“否”,为二叉树结构。所谓回归,就是根据特征向量来决定对应的输出值。回归树就是将特征空间划分成若干单元,每一个划分单元有一个特定的输出。因为每个结点都是“是”…

  • mysql5.7.17安装配置图文教程(sql2017安装步骤)

    本文详细介绍了Win10下MySQL5.7.27的安装及配置步骤,也列举出了一些常见的问题及解决方案

  • 服务器永恒之蓝病毒解决方法_永恒之蓝病毒作者

    服务器永恒之蓝病毒解决方法_永恒之蓝病毒作者一、NSA“永恒之蓝”勒索蠕虫全球爆发2017年5月12日爆发的WannaCry勒索病毒肆虐了全球网络系统,引起各国企业和机构极大恐慌。而这次受害最严重的是Windows系统,自然也被锁定为怀疑对象,有人认为正是因为该系统对于漏洞的麻木和疏漏才导致了此次勒索病毒的蔓延。作为受害者的微软却将矛头指向美国国安局(NSA)和永恒之蓝。不法分子利用…

    2022年10月16日
  • windows密码获取 — LC5暴力激活成功教程Hash密码「建议收藏」

    windows密码获取 — LC5暴力激活成功教程Hash密码「建议收藏」​错,可以改,那,错过呢。。。—-网易云热评一、首先用QuarksPwDump导出hash值并存储到1.txtquarkspwdump–dump-hash-local–output1.txt二、下载并安装LC5并注册1、下载地址:回复2、双击lc5setup一路下一步,3、将hashgen和lc5替换了原文件4、双击lc5,并打开注册机,点击administrator三、使用方法1、点击会话,导入1.txt…

  • LabelImg安装

    LabelImg安装LabelImg安装

  • java飞机大战_java飞机大战代码步骤解析

    java飞机大战_java飞机大战代码步骤解析一、简单介绍这是一个功能相对全的JAVA版坦克大战,界面绘制是通过JAVA的图形化用户界面完成的,包括了菜单界面和游戏界面。其中菜单界面可以供玩家选择重新开始游戏、暂停、继续、是否播放背景音乐、帮助等操作;游戏界面绘制了坦克、河流、草地、鹰碉堡等经典坦克场景,玩家在游戏界面操作坦克开始对战。本游戏使用的主要技术有Swing编程、面向对象编程、多线程编程。本…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号