Linux UDP编程流程

news/2024/5/18 11:52:20 标签: linux, udp, 单片机

文章目录

  • UDP编程流程
    • UDP协议无连接的特点
    • UDP协议数据报的特点

UDP编程流程

UDP 提供的是无连接、不可靠的、数据报服务。服务器端和客户端没有什么本质上的区别。编程流程如下:

在这里插入图片描述

socket()用来创建套接字,使用 udp 协议时,选择数据报服务 SOCK_DGRAM。sendto()用来发送数据,由于 UDP 是无连接的,每次发送数据都需要指定对端的地址(IP 和端口)。recvfrom()接收数据,每次都需要传给该方法一个地址结构来存放发送端的地址。recvfrom()可以接收所有客户端发送给当前应用程序的数据,并不是只能接收某一个客户端的数据。

服务器端代码ser.c如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int  main()
{   //1.创建套接字
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        printf("创建失败");
        exit(1);
    }

    struct sockaddr_in saddr,caddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
    
    //2.指定套接字的地址,绑定ip和端口
    int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
    if(res==-1)
    {
        printf("绑定失败");
        exit(1);
    }
    int len=sizeof(caddr);
    while(1)
    {
        char buff[128]={0};
    //3.接收客户端的消息,谁发来数据就接收谁的数据,并没有和任何客户端建立连接
        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
        //客户端的信息(ip和端口)存放到caddr,caddr指定数据的来源,中记录着是谁发的数据
        printf("buff(%d)=%s\n",ntohs(caddr.sin_port),buff);
    //4.向客户端回复数据
        sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
    }
}

客户端代码cli.c如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

int main()
{
    //1.创建套接字
    int sockfd=socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd==-1)
    {
        printf("创建失败");
        exit(1);
    }

    struct sockaddr_in saddr;//服务器的地址,ip和端口
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family=AF_INET;
    saddr.sin_port=htons(6000);
    saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

    int len =sizeof(saddr);
    while(1)
    {
        char buff[128]={0};
        printf("输入数据:");
        fgets(buff,128,stdin);

        if(strncmp(buff,"end",3)==0)
        {
            break;
        }

        //2.向服务器端发送数据
        sendto(sockfd,buff,sizeof(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));

        memset(buff,0,sizeof(buff));

        //3.接收服务器端回复的数据
        recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);

        printf("buff=%s\n",buff);
    }

    //4.关闭套接字
    close(sockfd);

}

运行结果:

在这里插入图片描述

从结果可以看出,当服务器端启动之后,可以同时启动多个客户端与客户端通信,但是两个客户端的端口号是不同的。

UDP协议无连接的特点

将服务器端关闭再重启后,客户端依旧可以与服务器端通信,如下图所示:

在这里插入图片描述
这是因为服务器端和客户端是没有建立连接的,当服务器端启动之后,收的到底是哪个客户端的消息我们并不知道,哪个客户端发消息,服务器端就收哪个客户端发来的消息。当服务器端关闭之后是不会像TCP编程那样有底层的协议去进行四次挥手通知客户端它要关闭的,客户端不会收到任何信息并且不知道服务器端是否关闭,所以当我们服务器端关闭之后再重新启动不会影响客户端向服务器端发送数据。同理,客户端关闭也不会给服务器端发送任何信息,客户端的关闭也不会影响服务器端。

如果服务器端关闭后,客户端向服务器端发送数据就会发生阻塞,阻塞在客户端的recvfrom这个地方,因为服务器没启动,端口没有人使用,那么数据就会被丢掉,所以没有服务器端给客户端回复数据,所以就会阻塞在recvfrom这个地方。如下图:

在这里插入图片描述

此时客户端代码cli.c执行完了sendto,接下来执行recvfrom的时候就被阻塞住了,因为没有服务器端给客户端回复消息,此时发送的aaaaaa发给本主机的6000端口,但是本主机的6000端口没有被占用,也就是6000端口没有被使用,所以所发送的数据aaaaaa就直接被丢掉了,所以也不会有服务器端给客户端回复消息,客户端就会在recvfrom这个地方阻塞住。

UDP协议数据报的特点

将服务器端代码ser.c中的recvfrom那一行的代码修改为如下情况,让服务器端一次只收一个字符:

recvfrom(sockfd,buff,1,0,(struct sockaddr*)&caddr,&len);

此时的运行结果:

在这里插入图片描述

出现这样的结果是因为,第一次客户端所发送的"hello",服务器端只收到了一个字符"h",剩下的"ello"被丢掉了,后续的结果也是一样,这是因为UDP协议是数据报服务,不像流式服务一样没有读完会继续读,每次recvfrom就拆一个包,拆一个包要保证把所有的数据都读走,不然剩余的数据就会被丢掉。所以在使用UDP协议的时候必须要保证一次把数据接收完。不用担心两个包合到一起导致收不完数据,因为每次调sendto的时候都要指定对方的地址,这个地址可以一样也可以不一样,所以两个sendto不可能合到一起,因为sendto的目的端可以不一样。不像TCP协议,send一下,再send一下,两次send的内容都会放到同一个缓冲区中,UDP协议是sendto直接打一个包过去,不会出现粘包的现象。数据报服务的特点如下图所示:

在这里插入图片描述


http://www.niftyadmin.cn/n/5025282.html

相关文章

如何使用极狐GitLab 支持 ISO 27001 合规

目录 组织控制 技术控制 了解更多 本文来源&#xff1a;about.gitlab.com 作者&#xff1a;Joseph Longo 译者&#xff1a;武让 极狐GitLab 高级解决方案架构师 作为一体化平台&#xff0c;通过极狐GitLab 可以很容易实现 DevSecOps 全生命周期管理。极狐GitLab 使开发人员能…

九、MySql表的内连和外连(重点)

文章目录 一、内连接&#xff08;一&#xff09;含义&#xff08;二&#xff09;语法&#xff08;三&#xff09;案例 二、外连接&#xff08;一&#xff09;左外连接1.语法2.案例 &#xff08;二&#xff09;右外连接1.语法2.案例3.练习 表的连接分为内连和外连&#xff01; 一…

面试中常见的算法题和其python实现

在面试中&#xff0c;常见的算法题包括排序算法、查找算法、动态规划、贪心算法等。以下是一些常见算法题及其Python实现示例&#xff1a; 1. 快速排序&#xff08;Quick Sort&#xff09;&#xff1a; 题目描述&#xff1a;给定一个数组&#xff0c;使用快速排序算法对数组进…

浅谈STL|STL函数对象篇

一.函数对象概念 概念: 重载函数调用操作符的类&#xff0c;其对象常称为函数对象 函数对象使用重载的()时&#xff0c;行为类似函数调用&#xff0c;也叫仿函数 本质: 函数对象(仿函数)是一个类&#xff0c;不是一个函数 特点 函数对象在使用时&#xff0c;可以像普通函数那…

还没用熟 TypeScript 社区已经开始抛弃了

根据 rich-harris-talks-sveltekit-and-whats-next-for-svelte 这篇文章的报道&#xff0c; Svelte 计划要把代码从 TS 换到 JS 了。 The team is switching the underlying code from TypeScript to JavaScript. That and the update will then allow the team to incorporate…

算法leetcode|80. 删除有序数组中的重复项 II(rust重拳出击)

文章目录 80. 删除有序数组中的重复项 II&#xff1a;样例 1&#xff1a;样例 2&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 80. 删除有序数组中的重复项 II&#xff1a; …

马来西亚市场最全开发攻略

东盟有十个国家&#xff0c;人口接近6亿&#xff0c;已连续13年成为我国最大贸易伙伴之一。数据显示&#xff0c;1-7月中国与东盟贸易总值为3.59万亿元&#xff0c;同比增长2.8%。东盟成员国中&#xff0c;与中国前三大贸易伙伴依次为越南、马来西亚和印度尼西亚。 今天来聊一…

【实战详解】如何快速搭建接口自动化测试框架?Python + Requests

摘要&#xff1a; 本文主要介绍如何使用Python语言和Requests库进行接口自动化测试&#xff0c;并提供详细的代码示例和操作步骤。希望能对读者有所启发和帮助。 前言 随着移动互联网的快速发展&#xff0c;越来越多的应用程序采用Web API&#xff08;也称为RESTful API&…