问题:如何扩大之前的通信框架,使其反对 UDP 通信,进而成为一个欠缺的网络通讯框架?

UDP 通信扩大

UDP 通信实体概要设计

  • 每个 UDP Point 位置对等(因为不用被动发动连贯),可通过 ip 地址和 port 号进行通信
  • UDP Point 数据收发单位为: Message 或 Byte
  • 在承受口设计上,与 TcpClient 保持一致(框架接口一致性)
  • 指标:封装原生 socket 细节,关注 UDP 通信逻辑

UDP 通信实体接口设计

typedef void UdpPoint;UdpPoint *UdpPoint_New(int port);UdpPoint *UdpPoint_From(int fd);void UdpPoint_Del(UdpPoint *point);int UdpPoint_SendMsg(UdpPoint *point, Message *msg, const char *remote, int port);int UdpPoint_SendRaw(UdpPoint *point, const char *buf, int length, const char *remote, int port);Message *UdpPoint_RecvMsg(UdpPoint *point, char *remote, int *port);int UdpPoint_RecvRaw((UdpPoint *point, const char *buf, int length, char *remote, int *port);int UdpPoint_Available(UdpPoint *point);void UdpPoint_SetData(UdpPoint *point, void *data);void *UdpPoint_GetData(UdpPoint *point);int UdpPoint_SetOpt(UdpPoint *point, int levle, int optname, const void *optval, unsigned int optlen);int UdpPoint_GetOpt(UdpPoint *point, int levle, int optname, void *optval, unsigned int *optlen);

要害代码实现

  • 因为 UDP 是以数据报形式进行通信(非数据流形式,报文间有显著边界)
  • 因而,不能间接通过 MParser_ReadFd(...) 解析出音讯
  • 必须先将报文残缺接管到内存中,再进行从内存中解析出音讯
  • 即通过 MParser_ReadMeme(...) 间接实现音讯解析
对于上述的补充

UDP 套接字的收发报文要用 sendto 和 recvfrom(能够类比 TCP 套接字的 connect 和 accept),参数外面会标识要发往的对端,或者要接管的对端的 IP 地址和端口;

对 UDP 套接字 connect 的行为也只会通知内核:”帮我做个过滤,我只关怀这个对端的报文“,已”连贯“的UDP套接字能够利用 read, write, recv, send 函数,通常如果确定了该实体只与一个对端进行通信,那么就抉择 connect;

[更重要的是 UDP 套接字的缓冲区是以一个个报文为单位进行排队的]调用一次 recvfrom 示意提取一个报文,和基于 TCP 基于字节流的形式是不同的。基于这样的起因咱们不能在 UDP 中先读取肯定的应用层 header, 而后再依据头部长度字段来优雅的读取具体数量的数据,这样会出错,产生凌乱,而在 TCP 中常常这么做。

编程试验: UDP 通信端设计与实现

udp_point.h
#ifndef UDP_POINT_H#define UDP_POINT_H#include "message.h"typedef void UdpPoint;UdpPoint *UdpPoint_New(int port);UdpPoint *UdpPoint_From(int fd);void UdpPoint_Del(UdpPoint *point);int UdpPoint_SendMsg(UdpPoint *point, Message *msg, const char *remote, int port);int UdpPoint_SendRaw(UdpPoint *point, const char *buf, int length, const char *remote, int port);Message *UdpPoint_RecvMsg(UdpPoint *point, char *remote, int *port);int UdpPoint_RecvRaw(UdpPoint *point, char *buf, int length, char *remote, int *port);int UdpPoint_Available(UdpPoint *point);void UdpPoint_SetData(UdpPoint *point, void *data);void *UdpPoint_GetData(UdpPoint *point);int UdpPoint_SetOpt(UdpPoint *point, int levle, int optname, const void *optval, unsigned int optlen);int UdpPoint_GetOpt(UdpPoint *point, int levle, int optname, void *optval, unsigned int *optlen);#endif // UDP_POINT_H
udp_point.c
#include "udp_point.h"#include "msg_parser.h"#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <arpa/inet.h>#include <unistd.h>#include <malloc.h>#include <string.h>typedef struct udp_point {    int fd;    MParser *parser;    void *data;}Point;static char g_temp[1024 * 4] = {0};static void ParserAddr(struct sockaddr_in addr, char *ip, int *port){    if (ip) {        strcpy(ip, inet_ntoa(addr.sin_addr));    }    if (port) {        *port = ntohs(addr.sin_port);    }}UdpPoint *UdpPoint_New(int port){    Point *ret = malloc(sizeof(Point));    struct sockaddr_in addr = {0};    int ok = !! ret;    addr.sin_family = AF_INET;    addr.sin_addr.s_addr = htonl(INADDR_ANY);    addr.sin_port = htons(port);    ok = ok && ((ret->parser = MParser_New()) != NULL);    ok = ok && ((ret->fd = socket(PF_INET, SOCK_DGRAM, 0)) != -1);    ok = ok && (bind(ret->fd, (struct sockaddr*)&addr, sizeof(addr)) != -1);    if (ok) {        ret->data = NULL;    } else {        ret ? (MParser_Del(ret->parser), NULL) : NULL;        ret ? close(ret->fd) : -1;        free(ret);        ret = NULL;    }    return ret;}UdpPoint *UdpPoint_From(int fd){    Point *ret = malloc(sizeof(Point));    if (ret) {        ret->fd = fd;        ret->parser = MParser_New();        ret->data = NULL;    }    return (ret && ret->parser) ? ret : (free(ret), NULL);}void UdpPoint_Del(UdpPoint *point){    Point *c = (Point*)point;    if (c) {        close(c->fd);        MParser_Del(c->parser);        free(c);    }}int UdpPoint_SendMsg(UdpPoint *point, Message *msg, const char *remote, int port){    int ret = 0;    Point *c = (Point*)point;     if (c && msg && remote) {        int len = Message_Size(msg);        char *data = (char*)Message_H2N(msg);        ret = UdpPoint_SendRaw(point, data, len, remote, port);        Message_N2H(msg);    }    return ret;   }int UdpPoint_SendRaw(UdpPoint *point, const char *buf, int length, const char *remote, int port){    int ret = 0;    Point *c = (Point*)point;     if (c && buf && remote) {        struct sockaddr_in raddr = {0};        int addrlen = sizeof(raddr);        raddr.sin_family = AF_INET;        raddr.sin_addr.s_addr = inet_addr(remote);        raddr.sin_port = htons(port);        ret = (sendto(c->fd, buf, length, 0, (struct sockaddr*)&raddr, addrlen) != -1);    }    return ret;}Message *UdpPoint_RecvMsg(UdpPoint *point, char *remote, int *port){       Message *ret = NULL;    Point *c = (Point*)point;     if (c) {        struct sockaddr_in raddr = {0};        int addrlen = sizeof(raddr);        int length = recvfrom(c->fd, g_temp, sizeof(g_temp), MSG_PEEK, (struct sockaddr*)&raddr, &addrlen);        char *buf = (length > 0) ? malloc(length) : NULL;        length = recvfrom(c->fd, buf, length, 0, (struct sockaddr*)&raddr, &addrlen);        if (length > 0) {            ret = MParser_ReadMem(c->parser, buf, length);        }        if (ret) {            ParserAddr(raddr, remote, port);        }        free(buf);    }        return ret;}int UdpPoint_RecvRaw(UdpPoint *point, char *buf, int length, char *remote, int *port){    int ret = 0;    Point *c = (Point*)point;     if (c && buf) {        struct sockaddr_in raddr = {0};        int addrlen = sizeof(raddr);        printf("===============================\n");        ret = recvfrom(c->fd, buf, length, 0, (struct sockaddr*)&raddr, &addrlen);        printf("===============================\n");        if (ret != -1) {            ParserAddr(raddr, remote, port);        }    }    return ret;}int UdpPoint_Available(UdpPoint *point){    int ret = -1;    Point *c = (Point*)point;     if (c) {        struct sockaddr_in raddr = {0};        int len = sizeof(raddr);        ret = recvfrom(c->fd, g_temp, sizeof(g_temp), MSG_PEEK | MSG_DONTWAIT, (struct sockaddr*)&raddr, &len);    }    return ret;   }void UdpPoint_SetData(UdpPoint *point, void *data){    Point *c = (Point*)point;    if (c) {        c->data = data;    }}void *UdpPoint_GetData(UdpPoint *point){    void *ret = NULL;    Point *c = (Point*)point;    if (c) {        ret = c->data;    }    return ret;}int UdpPoint_SetOpt(UdpPoint *point, int levle, int optname, const void *optval, unsigned int optlen){    int ret = -1;    Point *c = (Point*)point;    if (c) {        ret = setsockopt(c->fd, levle, optname, optval, optlen);    }    return ret;}int UdpPoint_GetOpt(UdpPoint *point, int levle, int optname, void *optval, unsigned int *optlen){    int ret = -1;    Point *c = (Point*)point;     if (c) {        ret = getsockopt(c->fd, levle, optname, optval, optlen);    }    return ret;  }
输入:
p = 0x55bd81ba4260ip: 192.168.2.24, port: 7777msg: 0x55bd81ba46e0msg->type = 1msg->cmd = 2msg->index = 3msg->total = 403 02 01

tcp_client 增加属性相干操作
int TcpClient_SetOpt(TcpClient *client, int levle, int optname, const void *optval, unsigned int optlen);int TcpClient_GetOpt(TcpClient *client, int levle, int optname, void *optval, unsigned int *optlen);// ...int TcpClient_SetOpt(TcpClient *client, int levle, int optname, const void *optval, unsigned int optlen){    int ret = -1;    Client *c = (Client*)client;    if (c) {        ret = setsockopt(c->fd, levle, optname, optval, optlen);    }    return ret;}int TcpClient_GetOpt(TcpClient *client, int levle, int optname, void *optval, unsigned int *optlen){    int ret = -1;    Client *c = (Client*)client;     if (c) {        ret = getsockopt(c->fd, levle, optname, optval, optlen);    }    return ret; }
tcp_server 增加属性相干操作
int TcpClient_SetOpt(TcpServer *server, int levle, int optname, const void *optval, unsigned int optlen);int TcpClient_GetOpt(TcpServer *server, int levle, int optname, void *optval, unsigned int *optlen);// ...int TcpServer_SetOpt(TcpServer *server, int levle, int optname, const void *optval, unsigned int optlen){    int ret = -1;    Server *s = (Server*)server;    if (s) {        ret = setsockopt(s->fd, levle, optname, optval, optlen);    }    return ret;}int TcpServer_GetOpt(TcpServer *server, int levle, int optname, void *optval, unsigned int *optlen){    int ret = -1;    Server *s = (Server*)server;    if (s) {        ret = getsockopt(s->fd, levle, optname, optval, optlen);    }    return ret;  }