问题:有了协定和协定解析器之后,能够干嘛?

TCP 通信框架设计

  • 客户端

    • 以协定音讯为根本单位收发数据
    • 同时反对字节为根本单位收发数据
  • 服务端

    • 负责监听链接,并产生通信客户端
    • 负责监听数据通讯状态,并给出告诉

职责意义

  • 客户端用于进行理论的双向数据通信

    • 数据发送 & 数据接管 (协定音讯)
  • 服务端仅用于监听和回调告诉

    • 事件类型:连贯,数据,断开
    • 事件回调:void (*Listener)(TcpClient *client, int event);

客户端接口设计

typedef void TcpClient;TcpClient *TcpClient_New();TcpClient *TcpClient_From(int fd);int TcpClient_SendMsg(TcpClient *client, Message *msg);int TcpClient_SendRaw(TcpClient *client, char *buf, int length);Message *TcpClient_RecvMsg(TcpClient *client);int TcpClient_RecvRaw(TcpClient *client, char *buf, int length);int TcpClient_Connect(TcpClient *client, char *ip, int port);int TcpClient_IsValid(TcpClient *client);void TcpClient_Close(TcpClient *client);void TcpClient_Del(TcpClient *client);void TcpClient_SetData(TcpClient *client, void *data);void *TcpClient_GetDate(TcpClient *client);

编程试验:客户端设计与实现

message.h
#ifndef MESSAGE_H#define MESSAGE_Htypedef struct message {    unsigned short type;    unsigned short cmd;    unsigned short index;    unsigned short total;    unsigned int length;    unsigned char payload[];}Message;Message *Message_New(unsigned short type,                    unsigned short cmd,                    unsigned short index,                    unsigned short total,                    unsigned char *payload,                    unsigned int length);int Message_Size(Message *m);Message *Message_N2H(Message *m);Message *Message_H2N(Message *m);#endif
message.c
#include "message.h"#include <malloc.h>#include <string.h>#include <arpa/inet.h>Message *Message_New(unsigned short type, unsigned short cmd, unsigned short index, unsigned short total, unsigned char *payload, unsigned int length){    Message *ret = malloc(sizeof(Message) + length);    if (ret) {        ret->type   = type;        ret->cmd    = cmd;        ret->index  = index;        ret->total  = total;        ret->length = length;        if (payload) {            memcpy(ret + 1, payload, length);        }    }    return ret;}int Message_Size(Message *m){    int ret = 0;    if (m) {        ret = sizeof(Message) + m->length;    }    return ret;}Message *Message_N2H(Message *m){    if (m) {        m->type = ntohs(m->type);        m->cmd = ntohs(m->cmd);        m->index = ntohs(m->index);        m->total = ntohs(m->total);        m->length = ntohl(m->length);      }    return m;}Message *Message_H2N(Message *m){    if (m) {        m->type = htons(m->type);        m->cmd = htons(m->cmd);        m->index = htons(m->index);        m->total = htons(m->total);        m->length = htonl(m->length);      }    return m;   }
msg_parser.h
#ifndef MSG_PARSER_H#define MSG_PARSER_H#include "message.h"typedef void MParser;MParser *MParser_New();Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length);Message *MParser_ReadFd(MParser *parser, int fd);void MParser_Reset(MParser *parse);void MParser_Del(MParser *parse);#endif
msg_parser.c
#include <malloc.h>#include <string.h>#include <arpa/inet.h>#include <unistd.h>#include "msg_parser.h"typedef struct msg_parser {    Message cache;    int header;    int need;    Message *msg;}MsgParser;static void InitState(MsgParser *p){    p->header = 0;    p->need = sizeof(p->cache);        free(p->msg);    p->msg = NULL;}static int ToMidState(MsgParser *p){    p->header = 1;    p->need = p->cache.length;    p->msg = malloc(sizeof(p->cache) + p->need);    if (p->msg) {        *p->msg = p->cache;    }    return !!p->msg;}static Message *ToLastState(MsgParser *p){    Message *ret = NULL;    if (p->header && !p->need) {        ret = p->msg;        p->msg = NULL;    }    return ret;}static int ToRecv(int fd, char *buf, int size){    int retry = 0;    int i = 0;    while (i < size) {        int len = read(fd, buf + i, size - i);        if (len > 0) {            i += len;        } else if (len < 0) {            break;        } else {            if (retry++ > 5) {                break;            }            usleep(200 * 1000);        }    }    return i;}MParser *MParser_New(){    MsgParser *ret = calloc(1,  sizeof(MsgParser));    InitState(ret);    return ret;}Message *MParser_ReadMem(MParser *parser, unsigned char *mem, unsigned int length){    Message *ret = NULL;    MsgParser *p = (MsgParser*)parser;    if (!p || !mem || !length) {        return ret;    }    if (!p->header) {        int len = (p->need < length) ? p->need : length;        int offset = sizeof(p->cache) - p->need;        memcpy((char*)&p->cache + offset, mem, len);        if (p->need == len) {            Message_N2H(&p->cache);            mem += p->need;            length -= p->need;            if (ToMidState(p)) {                ret = MParser_ReadMem(p, mem, length);            } else {                InitState(p);            }        } else {            p->need -= len;        }    } else {        if (p->msg) {            int len = (p->need < length) ? p->need : length;            int offset = p->msg->length - p->need;            memcpy(p->msg->payload + offset, mem, len);            p->need -= len;            if (ret = ToLastState(p)) {                InitState(p);            }        }      }    return ret;}Message *MParser_ReadFd(MParser *parser, int fd){    Message *ret = NULL;    MsgParser *p = (MsgParser*)parser;    if (fd == -1 || !p) {        return ret;    }    if (!p->header) {        int offset = sizeof(p->cache) - p->need;        int len = ToRecv(fd, (char*)&p->cache + offset, p->need);        if (len == p->need) {            Message_N2H(&p->cache);            if (ToMidState(p)) {                ret = MParser_ReadFd(p, fd);            }            else {                InitState(p);            }        }        else {            p->need -= len;        }    } else {        if (p->msg) {            int offset = p->msg->length - p->need;            int len = ToRecv(fd, p->msg->payload + offset, p->need);            p->need -= len;        }        if (ret = ToLastState(p)) {            InitState(p);        }    }     return ret;}void MParser_Reset(MParser *parse){    MsgParser *p = (MsgParser*)parse;    if (p) {        InitState(p);    }}void MParser_Del(MParser *parse){    MsgParser *p = (MsgParser*)parse;    if (p) {        free(p->msg);        free(p);    }}
tcp_client.h
#ifndef TCP_CLIENT_H#define TCP_CLIENT_H#include "message.h"typedef void TcpClient;TcpClient *TcpClient_New();TcpClient *TcpClient_From(int fd);int TcpClient_SendMsg(TcpClient *client, Message *msg);int TcpClient_SendRaw(TcpClient *client, char *buf, int length);Message *TcpClient_RecvMsg(TcpClient *client);int TcpClient_RecvRaw(TcpClient *client, char *buf, int length);int TcpClient_Connect(TcpClient *client, char *ip, int port);int TcpClient_IsValid(TcpClient *client);void TcpClient_Close(TcpClient *client);void TcpClient_Del(TcpClient *client);void TcpClient_SetData(TcpClient *client, void *data);void *TcpClient_GetDate(TcpClient *client);#endif
tcp_client.c
#include "tcp_client.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>typedef struct tcp_client {    int fd;    MParser *parser;    void *data;}Client;TcpClient *TcpClient_New(){    return TcpClient_From(-1);}TcpClient *TcpClient_From(int fd){    Client *ret = malloc(sizeof(Client));    if (ret) {        ret->fd     = fd;        ret->parser = MParser_New();        ret->data   = NULL;    }    return (ret && ret->parser) ? ret : (free(ret), NULL);}int TcpClient_SendMsg(TcpClient *client, Message *msg){    int ret = 0;    Client *c = (Client*)client;    if (c && msg) {        int len = Message_Size(msg);        char *data = (char*)Message_H2N(msg);        ret = (send(c->fd, data, len, 0) != -1);        Message_N2H(msg);    }    return ret;}int TcpClient_SendRaw(TcpClient *client, char *buf, int length){    int ret = 0;    Client *c = (Client*)client;    if (c && buf)  {        ret = send(c->fd, buf, length, 0);    }    return ret;}Message *TcpClient_RecvMsg(TcpClient *client){    Message *ret = NULL;    Client *c = (Client*)client;    if (c) {        ret = MParser_ReadFd(c->parser, c->fd);    }    return ret;}int TcpClient_RecvRaw(TcpClient *client, char *buf, int length){    int ret = 0;    Client *c = (Client*)client;    if (c && buf) {        ret = recv(c->fd, buf, length, 0);    }    return ret;}int TcpClient_Connect(TcpClient *client, char *ip, int port){    int ret = TcpClient_IsValid(client);    Client *c = (Client*)client;    if (!ret && ip && ((c->fd = socket(PF_INET, SOCK_STREAM, 0)) != -1)) {        struct sockaddr_in addr = {0};        addr.sin_family = AF_INET;        addr.sin_addr.s_addr = inet_addr(ip);        addr.sin_port = htons(port);        ret = (connect(c->fd, (struct sockaddr*)&addr, sizeof(addr)) != -1);    }    return ret;}int TcpClient_IsValid(TcpClient *client){           int ret = 0;    Client *c = (Client*)client;    if (c) {        struct tcp_info info = {0};        int l = sizeof(info);        getsockopt(c->fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&l);        ret = (info.tcpi_state == TCP_ESTABLISHED);    }    return ret;}void TcpClient_Close(TcpClient *client){    Client *c = (Client*)client;    if (c) {        close(c->fd);        c->fd = -1;        MParser_Reset(c->parser);    }}void TcpClient_Del(TcpClient *client){    Client *c = (Client*)client;    if (c) {        TcpClient_Close(c);        MParser_Del(c->parser);        free(c);    }   }void TcpClient_SetData(TcpClient *client, void *data){    Client *c = (Client*)client;    if (c) {        c->data = data;    }}void *TcpClient_GetDate(TcpClient *client){    void *ret = NULL;    Client *c = (Client*)client;    if (c) {        ret = c->data;    }    return ret;}
测试文件:client.c
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "message.h"#include "tcp_client.h"int main(){    int i = 0;    char *test = "D.T.Software";    Message *pm = NULL;    TcpClient *client = TcpClient_New();    if (client && TcpClient_Connect(client, "127.0.0.1", 8888)) {        printf("connect success\n");        for (i=0; i<strlen(test); ++i) {            char buf[2] = {0};            buf[0] = test[i];            pm = Message_New(128, 129, i, strlen(test), buf, 2);            TcpClient_SendMsg(client, pm);            free(pm);        }    }    getchar();    TcpClient_Del(client);    return 0;}
测试文件:server.c
#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netinet/tcp.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "msg_parser.h"#include "tcp_client.h"int main(){    int server = 0;    struct sockaddr_in saddr = {0};    struct sockaddr_in caddr = {0};    socklen_t asize = 0;    int client = 0;    server = socket(PF_INET, SOCK_STREAM, 0);    if (server == -1) {        printf("server socket error\n");        return -1;    }    saddr.sin_family = AF_INET;    saddr.sin_addr.s_addr = htonl(INADDR_ANY);    saddr.sin_port = htons(8888);    if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {        printf("server bind error\n");        return -1;    }    if (listen(server, 1) == -1) {        printf("server listen error\n");        return -1;    }    printf("server start success\n");    while (1) {        TcpClient *c = NULL;        struct tcp_info info = {0};        int l = sizeof(info);        asize = sizeof(caddr);        client = accept(server, (struct sockaddr*)&caddr, &asize);        if (client == -1) {            printf("client accept error\n");            return -1;        }        c = TcpClient_From(client);        printf("client: %d\n", client);        printf("addr: %p\n", c);        do {            Message *m = TcpClient_RecvMsg(c);            if (m) {                printf("payload = %s\n", m->payload);                free(m);            }        } while (TcpClient_IsValid(c));        printf("client socket is closed\n");        TcpClient_Del(c);    }    close(server);    return 0;}

输入:

server start successclient: 4addr: 0x5590019b9670payload = Dpayload = .payload = Tpayload = .payload = Spayload = opayload = fpayload = tpayload = wpayload = apayload = rpayload = eclient socket is closed