问题:有了协定和协定解析器之后,能够干嘛?
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