【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、关闭套接字
c 复制代码
// udpCli.c
// gcc udpCli.c -o udpCli
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

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;
}

✨2.2 udp客户端相关函数

  • socket 函数

    c 复制代码
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    int socket(int domain, int type, int protocol);

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

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

    c 复制代码
    #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);

    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、关闭套接字
c 复制代码
// udpSer.c
// gcc udpSer.c -o udpSer
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

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;
}

✨2.2 udp服务端相关函数

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

  • bind 函数

    c 复制代码
    #include <sys/types.h>          /* See NOTES */
    #include <sys/socket.h>
    int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

    bind函数将addr指定的地址分配给文件描述符sockfd引用的套接字。addrlen指定addr指向的地址结构的大小。

  • recvfrom 函数

    c 复制代码
     #include <sys/types.h>
     #include <sys/socket.h>
     ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                        struct sockaddr *src_addr, socklen_t *addrlen);

    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、端口。

如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

相关推荐
watermelonoops1 小时前
Deepin和Windows传文件(Xftp,WinSCP)
linux·ssh·deepin·winscp·xftp
疯狂飙车的蜗牛2 小时前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
远游客07134 小时前
centos stream 8下载安装遇到的坑
linux·服务器·centos
马甲是掉不了一点的<.<4 小时前
本地电脑使用命令行上传文件至远程服务器
linux·scp·cmd·远程文件上传
jingyu飞鸟4 小时前
centos-stream9系统安装docker
linux·docker·centos
XH华4 小时前
初识C语言之二维数组(下)
c语言·算法
超爱吃士力架5 小时前
邀请逻辑
java·linux·后端
fantasy_arch5 小时前
CPU性能优化-磁盘空间和解析时间
网络·性能优化
cominglately7 小时前
centos单机部署seata
linux·运维·centos
魏 无羡7 小时前
linux CentOS系统上卸载docker
linux·kubernetes·centos