基于UDP协议的接收和发送

本文详细介绍了UDP编程的框架,包括服务器端和客户端的流程,重点解析了UDP协议的常用函数如socket(), bind(), recvfrom(), sendto()等的使用。此外,还探讨了UDP编程中可能出现的问题,如数据丢失、乱序、连接控制以及流量控制等,并提出了相应的对策。" 118092428,11147246,SpringBoot整合MyBatis-Plus:快速入门,"['SpringBoot集成', 'MyBatis-Plus', '数据库操作', 'ORM框架']
摘要由CSDN通过智能技术生成

一、UDP编程框架

UDP进行程序设计可以分为客户端服务器端两部分:

  • 服务器端主要包含建立套接字、将套接字与地址结构进行绑定、读写数据、关闭套接字几个过程。

    • 客户端包括建立套接字、读写数据、关闭套接字几个过程。

      • 服务器端和客户端两个流程之间的主要差别在于对地址的绑定(bind())函数,客户端可以不用进行地址和端口的绑定操作。

1.UDP编程框图

UDP协议的程序设计框架如下图所示,客户端和服务器之间的差别在于服务器必须使用bind()函数来绑定侦听的本地UDP端口,而客户端则可以不进行绑定,直接发送到服务器地址的某个端口地址。
与TCP程序设计相比较,UDP缺少了connect()、listen()及accept()函数,这是用于UDP协议无连接的特性,不用维护TCP的连接、断开等状态。

在这里插入图片描述

①.UDP协议的服务器端流程

  1. UDP协议的服务器端程序设计的流程分为套接字建立、套接字与地址结构进行绑定、收发数据、关闭套接字等过程,分别对应于函数socket()、bind()、sendto()、recvfrom ()和close()。

  2. 建立套接字过程使用socket()函数,这个过程与TCP协议中的含义相同,不过建立的套接字类型为数据报套接字。

  3. 地址结构与套接字文件描述符进行绑定的过程中,与 TCP 协议中的绑定过程不同的是地址结构的类型

  4. 当绑定操作成功后,可以调用 recvfrom()函数从建立的套接字接收数据或者调用 sendto()函数向建立的套接字发送网络数据。当相关的处理过程结束后,需要调用 close()函数关闭套接字。

②.UDP协议的客户端流程

  1. UDP协议的客户端端程序设计的流程分为套接字建立、收发数据、关闭套接字等过程,分别对应于函数 socket()、sendto()、recvfrom()和close()。

  2. 建立套接字过程使用 socket()函数,这个过程与TCP 协议中的含义相同,不过建立的套接字类型为数据报套接字。

  3. 建立套接字之后,可以调用函数 sendto()向建立的套接字发送数据或者调用 recvfrom()函数从建立的套接字收网络数据。

  4. 当相关的处理过程结束后,需要调用 close()函数关闭套接字。

③.UDP协议服务器和客户端之间的交互

  1. UDP协议中服务器和客户端的交互存在于数据的收发过程中。

  2. 进行网络数据收发的时候,服务器和客户端的数据是对应的:客户端发送数据的动作,对服务器来说是接收数据的动作;客户端接收数据的动作,对服务器来说是发送数据的动作。

  3. UDP协议服务器与客户端之间的交互,与TCP 协议的交互相比较,缺少了二者之间的连接。这是由于 UDP 协议的特点决定的,因为UDP 协议不需要流量控制、不保证数据的可靠性收发,所以不需要服务器和客户端之间建立连接的过程。

2.UDP服务器编程框架

服务器流程主要分为下述6个部分,即建立套接字、设置套接字地址参数、进行端口绑定、接收数据、发送数据、关闭套接字等。

  1. 建立套接字文件描述符,socket()函数生成套接字文件描述符:
int s = socket(AF_INET, SOCK_DGRAM, 0);
  1. 设置服务器地址和侦听端口,初始化要绑定的网络地址结构:
	struct sockaddr addr_serv;
    addr_serv.sin_family = AF_INET;				/*地址类型为AF_INET*/
	addr_serv.sin_addr.s_addr = htonl(INADDR_ANY);	/*任意本地地址*/
	addr_serv.sin_port = htons(PORT_SERV);			/*服务器端口*/
  1. 绑定侦听端口,使用bind()函数,将套接字文件描述符和一个地址类型变量进行绑定:bind(s, (struct sockaddr*)&addr_serv, sizeof(addr_serv));

  2. recvfrom()函数接收客户端的网络数据。

  3. sendto()函数向服务器主机发送数据。

  4. close()函数释放资源。

3.UDP客户端编程框架

  • UDP协议的客户端流程分为套接字建立、设置目的地址和端口、向服务器发送数据、从服务器接收数据、关闭套接字5个部分。与服务器端的框架相比,少了 bind()部分。

    • 客户端程序的端口和本地的地址可以由系统在使用时指定

      • 在使用 sendto()和recvfrom ()的时候,网络协议栈会临时指定本地的端口和地址,流程如下:
  1. 建立套接字文件描述符, socket();
  2. 设置服务器地址和端口, struct sockaddr;
  3. 向服务器发送数据, sendto();
  4. 接收服务器的数据, recvfrom();
  5. 关闭套接字, close()。

二、UDP协议程序设计的常用函数

UDP协议常用的函数有 recv()/recvfrom ()、send()/sendto()、socket()、bind()等。当然这些函数同样可以用于TCP协议的程序设计。

1.建立套接字socket()和绑定套接字bind()

UDP 协议建立套接字的方式同TCP 方式一 样,使用socket()函数,只不过协议的类型使用 SOCK_DGRAM, 而不是SOCK_STREAM。例如下面是建立一 个UDP 套接字文件描述符的代码。

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

UDP协议使用bind()函数和TCP没有差别,将一个套接字描述符与地址结构绑定在一起,例:

struct sockaddr_in local;//本地地址信息
int from_len = sizeof(from);//地址结构的长度
local.sin_family = AF_INET; //协议族
local.sin_port = htons(8888);// 本地端口
local.sin_addr.s_addr = htonl(INADDR_ANY); //任意本地地址
s = socket(AF_INET, SOCK_DGRAM, 0); //初始化一 个IPv4族的数据报套接字
if (s == -1) {
   
	//检查是否正常初始化socket 
	perror("socket");
	exit(EXIT_FAILURE);
}
bind(s, (struct sockaddr*)&local, sizeof(local)); //套接字绑定

绑定函数 bind()使用的时机,函数bind()的作用是将一个套接字文件描述符与一个本地地址绑定在一 起,即把发送数据的端口地址和IP 地址进行了指定。例如在发送数据的时候,如果不进行绑定,则会临时选择一个随机端口。

2.接收数据recvfrom()/recv()

当客户端成功建立了一个套接字文件描述符并构建了合适的struct sockaddr 结构或者服务器端成功地将套接字文件描述符和地址结构绑定后,可以使用 recv()或者 recvfrom ()来接收到达此套接字文件描述符上的数据,或者在这个套接字文件描述符上等待数据的到来。

①.rrecv()函数和recvfrom()函数

函数原型:

#include<sys/types.h>
#include<sys/socket.h>
ssize_t recv(int s, void* buf, size_t len, int flags);
ssize_t recvfrom(int s, void* buf, size_t len, int flags, struct sockaddr* from, socklen_t* fromlen);
//s:正在监听端口的套接字文件描述符,由socket()生成。
//buf:接收数据缓冲区
//len:接收数据缓冲区大小,设置大小防止溢出
//from:指向本地的数据结构sockaddr_in的指针,接收数据时发送的地址信息放在这个结构中
//fromlen:所指内容的长度,可使用sizeof(struct sockaddr_in)获得。

recv() 函数和recvfrom()函数的返回值在出错的时候返回-1; 错误值保存在 errno 中,如下表。

成功的时候,函数将返回接收到的数据长度,数据的长度可以为0, 因此如果函数返回值为0, 并不表示发生了错误,仅能表示此时系统中接收不到数据。

在这里插入图片描述
注:函数 recvfrom()中的参数 from和fromlen均为指针,不要直接将地址结构类型和地址类型的长度传入函数中,需要进行取地址的运算。

②.使用recvfrom()函数的例子

先建立一个数据报套接字文件描述符s,在地址结构local设置完毕后,将套接字s与地址结构local绑定一起。

#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>
int main(int argc,char *argv[])
{
   
        int s;//套接字文件描述符
        struct sockaddr_in from;//发送方的地址信息
        struct sockaddr_in local;//本地的地址信息

        int from_len = sizeof(from);//地址结构的长度
        int n;//接收到的数据长度
        char buff[128];//接收数据缓冲区
        s = socket(AF_INET,SOCK_DGRAM,0);//初始化一 个IPv4族的数据报套接字
        if(s == -1){
   //检查是否正常初始化socket
                perror("socket");
                exit(EXIT_FAILURE);
        }

        local.sin_family = AF_INET; //协议族
        local.sin_port = htons(8888);// 本地端口
        local.sin_addr.s_addr = htonl(INADDR_ANY); //任意本地地址
        bind(s, (struct sockaddr*)&local
  • 6
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值