UDP通信 [补档-2023-07-22]

发布时间 2024-01-13 18:08:55作者: 小白同学_C

UDP通信

6-1 简介

​ UDP通信是面向无链接的,不稳定,不可靠,不安全的一种通信方式。TCP在通信前发送方会向接收方进行三次握手链接,然后确认双方链接后才会进行数据传输,最后四次挥手保证链接关闭。而UDP不会三次握手四次挥手,它会直接向发送方发送数据,无论接收方是否会收到,所以UDP更适合在稳定的网络环境中使用。

6-2 UDP通信相关函数

6-2-1 recvfrom函数

头文件:#include <sys/socket.h>

函数原型:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

函数功能:接收消息。如果没有数据到来函数会一直阻塞,直到有数据到来或者发送错误。

函数参数

sockfd:套接字。

buf:用于存放接收消息的缓冲区。

len:缓冲区的长度。

flags:标志位,一般填0。

src_addr:返回发送方的地址信息,包括ip和端口号

addrlen:表示scr_addr指向的缓冲区大小,作为输出参数表示实际发送方地址的长度。

函数返回值

成功:返回接收的数据的字节数量。

失败:返回-1。

发送错误:返回-1

6-2-2 sendto函数

头文件:#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);

函数功能:发送数据。

函数参数

sockfd:套接字。

buf:指向要发送的数据的缓冲区。

len:要发送的数据的长度。

flags:传输标志,用于控制发送过程的行为,通常设置为0。

dest_addr:指向目标地址的指针,其中包含目标ip和端口号信息。

addrlen:目标地址结构体的长度。

函数返回值

成功:返回实际发送的字节数。

错误:返回-1。

6-3 使用UDP通信的服务端编写步骤

​ 第一步:创建一个套接字,但是socket函数的第二个参数要填 SOCK_DGRAM来将协议改为UDP

​ 第二步:将刚才创建的套接字与本地地址绑定。

​ 第三步:进入一个循环然后使用recvfrom函数来接收数据,接收到数据可以处理数据,然后使用sendto将处理好的数据回应给客户端。

​ 第四步:重复第三步,如果服务端需要关闭了记得关闭掉第一步创建的套接字描述符。

6-4 使用UDP通信的客户端编写步骤

​ 第一步:创建一个套接字,但是socket函数的第二个参数要填 SOCK_DGRAM来将协议改为UDP

​ 第二步:可以根据实际开发的需要,进入一个循环体持续收发数据或者是只收发一次数据。收发数据的函数就是上面的那两个。

​ 第三步:重复第二步,如果不需要发送数据了记得关闭第一步创建的套接字。

6-5 服务端代码示例

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netiner/in.h>
#include <ctype.h>
#include <sys/socket.h>

 

int main()

{

  //创建套接字,记得使用SOCK_DGRAM

  int cfd = socket(AF_INET, SOCK_DGRAM,0);

  if (cfd < 0) {

​     perror("创建套接字失败!");

​     return -1;

  }

  

  struct sockaddr_in serv;//用来保存服务端地址信息,用来绑定地址

  struct sockaddr_in clie;//用来保存客户端地址信息,一会用于通信

  serv.sin_family = AF_INET;

  serv.sin_port = htons(10066);

  serv.sin_addr.s_addr = htonl(INDAAR_ANY);

  bind(cfd, (struct sockaddr*)&serv, sizeof(serv));

 

  int n;//用来记录recvfrom从客户端接收了多少个字节的数据

  char data[100];//用来存储来自客户端的信息

  char serv_data[100] = "服务端已经接收到数据"; //服务端的回应

  socklen_t len;//用来记录客户端地址信息的大小

  while (1) {

​     //读数据

​     memset(data, 0x00, sizeof(data));//初始化

​     len = sizeof(clie);//记录大小

​     //接收数据

​     n = recvfrom(cfd, data, szieof(data), 0, (struct sockaddr*)&clie, &len);

 

​     //发数据(处理数据)

​     sendto(cfd, serv_data, n, 0, (struct sockaddr *)&clie,len);

  }

  //关闭套接字

  close(cfd);

}

6-6 客户端代码示例

点击查看代码
//udp客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <ctype.h>

 

int main()

{

  //创建socket

  int cfd = socket(AF_INET, SOCK_DGRAM, 0);

  if (cfd < 0)

  {

​     perror("socket error");

​     return -1;

  }

 

  int n;

  char buf[1024];

  struct sockaddr_in serv;

  serv.sin_family = AF_INET;

  serv.sin_port = htons(8888);

  inet_pton(AF_INET, "127.0.0.1", &serv.sin_addr.s_addr);

 

  while (1)

  {

​     //读标准输入数据

​     memset(buf, 0x00, sizeof(buf));

​     n = read(STDIN_FILENO, buf, sizeof(buf));

 

​     //发送数据

​     sendto(cfd, buf, n, 0, (struct sockaddr*)&serv, sizeof(serv));

 

​     //读取数据

​     memset(buf, 0x00, sizeof(buf));

​     n = recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL);

​     printf("n==[%d], buf==[%s]\n", n, buf);

  }

 

  //关闭套接字

  close(cfd);

 

  return 0;

}