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

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

相关推荐
椎名澄嵐36 分钟前
★ OJ题 ★ 二叉树
c语言·开发语言·数据结构·算法
jieshenai39 分钟前
linux neo4j 切换知识图谱
linux·知识图谱·neo4j
z35519069471 小时前
go的并发模型
网络·数据库
小安运维日记1 小时前
Linux云计算 |【第二阶段】SECURITY-DAY2
linux·运维·服务器·云计算·zabbix
互联网资讯1 小时前
本地生活服务商系统如何利用本地推获得更多曝光?
大数据·运维·网络·人工智能·生活
define_mine2 小时前
我的香橙派闹钟-v0.1 mini
linux·python·嵌入式硬件
马哥成长记2 小时前
“解锁进程间高效沟通,Linux IPC是你的关键钥匙!“#Linux系统编程之进程间通信【下】
linux·c语言·学习
Navigator_Z2 小时前
LeetCode //C - 327. Count of Range Sum
c语言·算法·leetcode
EastWood20132 小时前
C语言:科目二【基础知识】
c语言·开发语言
极客代码2 小时前
C语言宏的深度探索与全面应用策略
c语言·开发语言