admin 管理员组文章数量: 887021
RAW
UDP
- UDP 是 User Datagram Protocol 的简称,中文名是用户数据报协议,是一种无连接、不可靠的协议,它只是简单地实现从一端主机到另一端主机的数据传输功能,这些数据通过 IP 层发送,在网络中传输,到达目标主机的顺序是无法预知的。
- 在发送的一端,UDP 只是把上层应用的数据封装到 UDP 报文中(直接就添加了个UDP首部),在差错检测方面,仅仅是对数据进行了简单的校验,然后将其封装到 IP 数据报中发送出去。(也就是封装好了,直接发送出去,然后什么都不管了)
- 在接收端,无论是否收到数据,它都不会产生一个应答发送给源主机,并且如果接收到数据发送校验错误,那么接收端就会丢弃该 UDP 报文,也不会告诉源主机,这样子传输的数据是无法保障其准确性的,如果想要其准确性,那么就需要应用程序来保障了。(直接拆包,检验错误就直接丢弃)
- 与 TCP 协议一样,UDP 报文协议根据对应的端口号传递到目标主机的应用线程
- 支持一对一,一对多,多对一,多对多的交互通信。(而TCP只能一对一)
UDP 控制块
- 与 TCP 协议一样,为了更好管理 UDP 报文,LwIP 定义了一个 UDP 控制块
- 记录与 UDP 通信的所有信息,如源端口号、目标端口号、源 IP 地址、目标 IP 地址以及收到数据时候的回调函数等等
- 系统会为每一个基于 UDP 协议的应用线程创建一个 UDP 控制块,并且将其与对应的端口绑定,这样子就能进行 UDP 通信了
- 与 TCP 协议一样,LwIP 会把多个这样子的 UDP 控制块用一个链表连接起来,在处理的时候遍历列表,然后对控制块进行操作
struct udp_pcb
{IP_PCB; //宏IP_PCB中的各个字段struct udp_pcb *next; //指向udp_pcb,用于将控制块组织成链表u8_t flags; //控制块状态字段u16_t local_port, remote_port; //本地端口号和目的端口号udp_recv_fn recv; //处理数据的回调函数void *recv_arg; //传递给回调函数(就上面这个)的参数
};
IP_PCB:
- IP层的宏定义,应该就是给IP层用的
- 里面包括 IP 层需要使用的信息,如本地 IP 地址与目标 IP 地址(或者称为远端 IP 地址),服务类型、网卡、生存时间等
/* This is the common part of all PCB types. It needs to be at thebeginning of a PCB type definition. It is located here so thatchanges to this common part are made in one location instead ofhaving to change all PCB structs. */
#define IP_PCB \/* ip addresses in network byte order */ \ip_addr_t local_ip; \ //本机ipip_addr_t remote_ip; \ //目的端口号/* Socket options */ \u8_t so_options; \/* Type Of Service */ \u8_t tos; \/* Time To Live */ \u8_t ttl \/* link layer address resolution hint */ \IP_PCB_ADDRHINT
flags:
#define UDP_FLAGS_NOCHKSUM 0x01U //不进行帧校验和
#define UDP_FLAGS_UDPLITE 0x02U
#define UDP_FLAGS_CONNECTED 0x04U //已经建立连接了(就是访问了,UDP是不建立连接的,数据传输了就好了)
#define UDP_FLAGS_MULTICAST_LOOP 0x08U
端口号:
- 本地端口号与目标(远端)端口号
- UDP 协议就是根据这些端口号识别应用线程,当 UDP 收到一个报文的时候,会遍历链表上的所有控制块,根据报文的目标端口号找到与本地端口号相匹配的 UDP 控制块,然后递交数据到上层应用,而如果找不到对应的端口号,那么就会返回一个端口不可达 ICMP 差错控制报文。
recv:是一个函数指针(也就说回调函数),当UDP接收到数据后,就通过这个函数对数据进行处理
- 使用 NETCONN API 或者是 Socket API 编程,是不需要我们自己去注册回调函数recv_udp(),因为这个函数 LwIP 内核会自动给我们注册
/** Function prototype for udp pcb receive callback functions* addr and port are in same byte order as in the pcb* The callback is responsible for freeing the pbuf* if it's not used any more.** ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf* makes 'addr' invalid, too.** @param arg user supplied argument (udp_pcb.recv_arg) 就是控制块中写到的参数* @param pcb the udp_pcb which received data * @param p the packet buffer that was received 接收到的数据* @param addr the remote IP address from which the packet was received 发送数据端的IP地址* @param port the remote port from which the packet was received 发送数据端的端口号*/typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p,ip_addr_t *addr, u16_t port);
API
err
err_t err;
/** Definitions for error constants. */
typedef enum {
/** No error, everything OK. */ERR_OK = 0,
/** Out of memory error. */ERR_MEM = -1,
/** Buffer error. */ERR_BUF = -2,
/** Timeout. */ERR_TIMEOUT = -3,
/** Routing problem. */ERR_RTE = -4,
/** Operation in progress */ERR_INPROGRESS = -5,
/** Illegal value. */ERR_VAL = -6,
/** Operation would block. */ERR_WOULDBLOCK = -7,
/** Address in use. */ERR_USE = -8,
/** Already connecting. */ERR_ALREADY = -9,
/** Conn already established.*/ERR_ISCONN = -10,
/** Not connected. */ERR_CONN = -11,
/** Low-level netif error */ERR_IF = -12,/** Connection aborted. */ERR_ABRT = -13,
/** Connection reset. */ERR_RST = -14,
/** Connection closed. */ERR_CLSD = -15,
/** Illegal argument. */ERR_ARG = -16
} err_enum_t;
新建控制块 udp_new()
在使用 UDP 协议进行通信之前,必须创建一个 UDP 控制块,然后将控制块与对应的端口号进行绑定,才能发送报文,而在接收 UDP 报文的时候,这个端口号就是 UDP 报文唯一识别的标志,否则 UDP 报文将无法递交到应用层去处理,即无法通过 UDP 控制块的接收回调函数递交给应用层,新建控制块的函数很简单,就是在内存池中申请一个 MEMP_UDP_PCB 类型的内存块,用于存放 UDP 控制块的相关信息,并将其初始化为 0
//使用
udppcb=udp_new();//新建一个UDP控制块
/*** @ingroup udp_raw* Creates a new UDP pcb which can be used for UDP communication. The* pcb is not active until it has either been bound to a local address* or connected to a remote address.** @return The UDP PCB which was created. NULL if the PCB data structure* could not be allocated.** @see udp_remove()*/
struct udp_pcb *
udp_new(void)
{struct udp_pcb *pcb;LWIP_ASSERT_CORE_LOCKED();pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);/* could allocate UDP PCB? */if (pcb != NULL) {/* UDP Lite: by initializing to all zeroes, chksum_len is set to 0* which means checksum is generated over the whole datagram per default* (recommended as default by RFC 3828). *//* initialize PCB to all zeroes */memset(pcb, 0, sizeof(struct udp_pcb));pcb->ttl = UDP_TTL;
#if LWIP_MULTICAST_TX_OPTIONSudp_set_multicast_ttl(pcb, UDP_TTL);
#endif /* LWIP_MULTICAST_TX_OPTIONS */}return pcb;
}
建立会话 udp_connect()
- 说明:本来是想写建立连接的,但是对于 UDP 协议来说,建立连接的这种说法并不太准确,因为 UDP 协议本身就是一个无连接协议,因此,我们就说建立 UDP 会话好了。
- 因为UDP是直接发送不需要建立连接之后再发送数据。
- 这个函数的作用:1、设置控制块中的远端 IP 地址与端口号。2、然后将 UDP 控制块的状态设置为会话状态 UDP_FLAGS_CONNECTED。3、并且将 UDP 控制块插入 udp_pcbs 链表中
//举例 第一个参数控制块 目的ip(要给地址) 目的端口号
err=udp_connect(udppcb,&rmtipaddr,UDP_DEMO_PORT);//UDP客户端连接到指定IP地址和端口号的服务器
/*** Connect an UDP PCB.** This will associate the UDP PCB with the remote address.** @param pcb UDP PCB to be connected with remote address ipaddr and port.* @param ipaddr remote IP address to connect with.* @param port remote UDP port to connect with.** @return lwIP error code** ipaddr & port are expected to be in the same byte order as in the pcb.** The udp pcb is bound to a random local port if not already bound.** @see udp_disconnect()*/
err_t
udp_connect(struct udp_pcb
本文标签: raw
版权声明:本文标题:RAW 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/free/1700274223h375037.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论