😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍网络编程入门知识:UDP协议、UDP客户端、UDP服务端 🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你------泰戈尔🍭
⏰发布时间⏰:2024-02-29 09:23:52
本文未经允许,不得转发!!!
目录
- 🎄一、UDP协议概述
- 🎄二、一个最简单的UDP客户端
-
- [✨2.1 udp客户端步骤和代码](#✨2.1 udp客户端步骤和代码)
- [✨2.2 udp客户端相关函数](#✨2.2 udp客户端相关函数)
- 🎄三、一个最简单的UDP服务端
-
- [✨2.1 udp服务端步骤和代码](#✨2.1 udp服务端步骤和代码)
- [✨2.2 udp服务端相关函数](#✨2.2 udp服务端相关函数)
- 🎄四、总结
🎄一、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套接字
socket
:SOCK_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套接字
socket
:SOCK_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、端口。
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁