• 【Linux C | 网络编程】入门知识:UDP协议、一个最简单的UDP客户端、一个最简单的UDP服务端


    😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
    🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
    🤣本文内容🤣:🍭介绍网络编程入门知识:UDP协议、UDP客户端、UDP服务端 🍭
    😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭
    ⏰发布时间⏰:2024-02-29 09:23:52

    本文未经允许,不得转发!!!


    在这里插入图片描述

    🎄一、UDP协议概述

    UDP协议是一个简单的传输层协议,在RFC 768 [Postel 1980]中有详细说明。应用进程往一个UDP套接字写入一个消息,该消息随后被封装( encapsulating)到一个UDP数据报,该UDP数据报进而又被封装到一个IP数据报,然后发送到目的地。UDP不保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证每个数据报只到达一次。


    UDP协议的几个特点:

    • 1、UDP提供无连接服务。UDP客户端与UDP服务端不必存在任何长期的关系。一个UDP客户端可以发送一个数据报给一个UDP服务端,然后又立即发送另一个数据报给另一个UDP服务端。同样地,UDP服务端可以用一个UDP套接字接收多个UDP客户端数据。
    • 2、UDP是不可靠性。UDP不保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证每个数据报只到达一次。
      TCP会给每个分节关联一个序列号,如果接收到重复数据,可以判定数据重复并丢弃。
    • 3、每个数据报都有一个长度,并随着数据报一并传递给接收端进程。不同于没有任何记录边界的字节流协议TCP。

    在这里插入图片描述

    🎄二、一个最简单的UDP客户端

    ✨2.1 udp客户端步骤和代码

    编写UDP客户端的步骤:

    • 1、创建UDP套接字socketSOCK_DGRAM
    • 2、准备UDP服务端ip和端口,bzero、inet_pton
    • 3、使用sendto、recvfrom交互数据;
    • 4、关闭套接字
    // udpCli.c
    // gcc udpCli.c -o udpCli
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
    	// 1、创建UDP套接字socket
    	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    	if(sockfd<0)
    		perror("socket error" );
    	
    	// 2、准备服务端ip和端口
    	struct sockaddr_in servaddr;
    	bzero(&servaddr, sizeof(servaddr));
    	servaddr.sin_family = AF_INET;
    	servaddr.sin_port = htons (10086);
    	if (inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr) <= 0) // 设置本机IP为服务端IP
    		perror("inet_pton error");
    		
    	// 3、使用 sendto、recvfrom 交互数据
    	if(sendto(sockfd, "Hello,I am udp client", strlen("Hello,I am udp client"), 0, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    		perror("sendto error" );
    	
    	char recvline[256];
    	int n = 0;
    	while ( (n = recvfrom (sockfd, recvline, sizeof(recvline), 0, NULL, NULL)) > 0)
    	{
    		recvline[n] = 0 ;/*null terminate */
    		printf("recv[%s]\n",recvline);
    	}
    	
    	if (n < 0)
    		perror("read error" );
    	
    	// 4、关闭
    	close(sockfd);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    ✨2.2 udp客户端相关函数

    • socket 函数

      #include           /* See NOTES */
      #include 
      int socket(int domain, int type, int protocol);
      
      • 1
      • 2
      • 3

      socket函数创建一个套接字描述符。man手册描述,socket创建一个通信端点并返回一个描述符。

      • 参数domain指定通信域,使用了AF_INET,表示是IPv4 Internet protocols协议的。
      • 参数type指定套接字类型,使用``,表示TCP协议的套接字(提供有序、可靠、双向、基于连接的字节流。可以支持带外数据传输机制)。
      • 参数protocol指定了要与套接字一起使用的特定协议。通常,在给定的协议族中,只有一个协议支持特定的套接字类型,在这种情况下,协议可以指定为0。
    • sendto函数

      #include 
      #include 
      ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                        const struct sockaddr *dest_addr, socklen_t addrlen);
      
      • 1
      • 2
      • 3
      • 4

      sendto 函数将数据发送到指定的IP地址,一般在UDP协议使用。前面三个参数跟write函数一致,第4个参数是一个标志,最后两个参数跟connect函数的后两个参数一样,用来指定对端IP和端口。
      写一个长度为0的数据报是可行的。在UDP情况下,这会形成一个只包含一个IP首部(对于IPv4通常为20个字节,对于IPv6通常为40个字节)和一个8字节UDP首部而没有数据的IP数据报。


    在这里插入图片描述

    🎄三、一个最简单的UDP服务端

    ✨2.1 udp服务端步骤和代码

    编写UDP服务端的步骤:

    • 1、创建UDP套接字socketSOCK_DGRAM
    • 2、准备服务端ip和端口;
    • 3、绑定,bind
    • 4、使用sendto、recvfrom交互数据;
    • 5、关闭套接字
    // udpSer.c
    // gcc udpSer.c -o udpSer
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
    	// 1、创建UDP套接字socket
    	int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    	if(sockfd<0)
    		perror("socket error" );
    	
    	// 2、准备服务端ip和端口
    	struct sockaddr_in servaddr;
    	bzero(&servaddr, sizeof(servaddr));
    	servaddr.sin_family = AF_INET;
    	servaddr.sin_port = htons (10086);
    	servaddr.sin_addr.s_addr = INADDR_ANY; // 指定ip地址为 INADDR_ANY,这样要是服务器主机有多个网络接口,服务器进程就可以在任一网络接口上接受客户端的连接
    	
    	// 3、绑定 bind
    	if (bind(sockfd,(struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
    		perror("bind error" );
    	
    	// 4、使用 sendto、recvfrom 交互数据
    	
    	printf("UdpSer sockfd=%d, start \n",sockfd);
    	char recvline[256];
    	while(1)
    	{
    		struct sockaddr_in cliaddr;
    		bzero(&cliaddr, sizeof(cliaddr));
    		socklen_t addrLen=sizeof(cliaddr);
    		int n = recvfrom(sockfd, recvline, sizeof(recvline), 0, (struct sockaddr*)&cliaddr, &addrLen);
    		if(n>0)
    		{
    			recvline[n] = 0 ;/*null terminate */
    			printf("recv sockfd=%d %d byte, [%s] addrLen=%d, cliIp=%s, cliPort=%d\n",
    				sockfd, n, recvline, addrLen, inet_ntoa(cliaddr.sin_addr),cliaddr.sin_port);
    			sendto(sockfd, "Hello,I am udp server", strlen("Hello,I am udp server"), 0, (struct sockaddr*)&cliaddr, addrLen);
    		}
    	}
    	
    	// 5、关闭
    	close(sockfd);
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    ✨2.2 udp服务端相关函数

    tcp服务端相关函数有:socket、bind、recvfrom、sendto。socket、sendto函数可以参照上面 2.2 小节。

    • bind 函数
      #include           /* See NOTES */
      #include 
      int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
      
      • 1
      • 2
      • 3
      bind函数将addr指定的地址分配给文件描述符sockfd引用的套接字。addrlen指定addr指向的地址结构的大小。
    • recvfrom 函数
       #include 
       #include 
       ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                          struct sockaddr *src_addr, socklen_t *addrlen);
      
      • 1
      • 2
      • 3
      • 4
      recvfrom 函数从套接字接收数据,并且将对端的IP和端口号通过src_addr变量返回。前三个参数与read函数一样,第4个参数是一个标志,最后两个参数跟accept函数的后两个参数一样,用来获取对端IP和端口,addrlen是一个值-结果参数。
      对于UDP协议,recvfrom返回0也是可接受的,表示对端发了一个长度为0的数据报。不像TCP协议那样,read返回0表示对端关闭。

    在这里插入图片描述

    🎄四、总结

    👉本文主要介绍Linux下网络编程的基础知识,先是简单介绍一下UDP协议,然后给出一个UDP客户端、UDP服务端最简单的例子,最后介绍创建UDP客户端、UDP服务端需要用到的函数。
    在这里插入图片描述

    上面的UDP例子由于只演示最简单的方法,会存在的一些问题:
    1、数据报丢失没处理。可以设置超时、应答等方法来增加可靠性。
    2、没有验证收到的数据。没有验证发送者的IP、端口。

    在这里插入图片描述
    如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

  • 相关阅读:
    ubuntu22sshd服务保持连接的设置
    AI智能伪原创工具:原创文章自动生成的革新
    ARM Day2
    如何使用 ArcGIS Pro 制作边界晕渲效果
    [从零开始学习FPGA编程-43]:视野篇 - 后摩尔时代”芯片设计的技术演进-2-演进方向
    常见的引起膀胱结石的六大原因
    【尚硅谷 Vue学习笔记】p31列表过滤 p32列表排序
    C - Check The Text(string)
    Kotlin内置函数之apply、let、run、with
    沉睡者IT - 说几个2022年网络上比较好赚钱的创业项目
  • 原文地址:https://blog.csdn.net/wkd_007/article/details/136316871