This code is based on the Linux Epoll mechanism, using socket fd identifier to establish the linked list and the corresponding buffer.
tpack.h
#ifndef TPACK_H_ #define TPACK_H_ #include "define.h" // Communication Packet Structure #Define TPACK_HEAD_SIZE 512// Header information set to maximum first #Define TPACK_HEAD_DATA_SIZE 64// Standard Size #define TPACK_DATA_SIZE 8192 #define TPACK_SIZE 8192 + 512 #define TPACK_HEAD_LINE_TAG "\r\n" #Define TPACK_HEAD_TAG " r n106258 r n" // Head End Character #define TPACK_HEAD_TAG_SIZE strlen(TPACK_HEAD_TAG) #Define TPACK_DATA_TAG " r n4641 r n" // data Terminator #define TPACK_DATA_TAG_SIZE strlen(TPACK_DATA_TAG) // Suggested Buffer Size for Receiving Packets #Define TPACK_CACHE_SIZE TPACK_SIZE* 2// The recommended buffer length for a packet is twice the size of a packet // Packet command typedef unsigned int TPackCmd; #Define TPACK_CMD_EMPTY 0x1// empty command to keep #Define TPACK_CMD_SEND 0x2// T-end data to Client #Define TPACK_CMD_T_CLOSE 0x4// target to be disconnected #Define the target under TPACK_CMD_T_CLOSE 0x8// target to close, S to close, and point to the socket client #Define TPACK_CMD_T_LOGIN 0x10// target request for login, return user_token and task list after validation #define TPACK_CMD_5 0x20 #define TPACK_CMD_6 0x40 #define TPACK_CMD_7 0x80 // Package Form #define TPACK_FORM_SERVER "Server" #define TPACK_FORM_CLIENT "Client" #define TPACK_FORM_TARGET "Target" // Packet format typedef struct ST_TPACK_INFO { TPackCmd cmd; char form[TPACK_HEAD_DATA_SIZE]; uint sock_cli; // Client sock identity returned by server uint h_data_len; char* phead; uint phead_len; char* pdata; uint pdata_len; char* pstr; // Serialized data uint pstr_len; } *TPack; TPack tpack_new( TPackCmd cmd, char* form, uint sock, char* data, size_t size); void tpack_update_head(TPack tpack); char* tpack_tostr(TPack tpack); void tpack_free(TPack tpack); TPack tpack_parse(char* str, uint str_len, char **end); #endif
tpack.c
#include "stdafx.h" #include "com.h" #include "tpack.h" /** * Communication Packing and Disassembly */ // Creating packages is currently a direct application for maximum space. Later, it is necessary to create headers, create data and then synthesize packages. TPack tpack_new( TPackCmd cmd, char* form, uint sock, char* data, size_t size){ TPack tpack = (TPack) malloc( sizeof(struct ST_TPACK_INFO) ); memset( tpack, 0, sizeof(struct ST_TPACK_INFO) ); tpack->cmd = cmd; strncpy( tpack->form, form, strlen(form) ); tpack->sock_cli = sock; // Create maximum space for headers and data areas tpack->phead = (char *) malloc( TPACK_HEAD_SIZE ); memset( tpack->phead, 0, TPACK_HEAD_SIZE ); tpack->pdata = (char *) malloc( TPACK_DATA_SIZE ); memset( tpack->pdata, 0, TPACK_DATA_SIZE ); memcpy( tpack->pdata, data, size); tpack->pdata_len = strlen( tpack->pdata ); tpack_update_head(tpack); return tpack; } // Update header information, no header Terminator void tpack_update_head(TPack tpack) { sprintf( tpack->phead, "Command: %d%sFrom: %s%sSocket-Clint: %d%sData-Size: %d", tpack->cmd, TPACK_HEAD_LINE_TAG, tpack->form, TPACK_HEAD_LINE_TAG, tpack->sock_cli, TPACK_HEAD_LINE_TAG, tpack->pdata_len); tpack->phead_len = strlen( tpack->phead ); return; } // Release TPack char* tpack_tostr(TPack tpack) { tpack_update_head(tpack); tpack->pstr = (char *) malloc( TPACK_SIZE ); memset( tpack->pstr, 0, TPACK_SIZE ); // marger, using strlen to calculate length memcpy( tpack->pstr, tpack->phead, tpack->phead_len ); memcpy( tpack->pstr + strlen(tpack->pstr), TPACK_HEAD_TAG, TPACK_HEAD_TAG_SIZE ); memcpy( tpack->pstr + strlen(tpack->pstr), tpack->pdata, tpack->pdata_len ); memcpy( tpack->pstr + strlen(tpack->pstr), TPACK_DATA_TAG, TPACK_DATA_TAG_SIZE ); tpack->pstr_len = tpack->phead_len + TPACK_HEAD_TAG_SIZE + tpack->pdata_len + TPACK_DATA_TAG_SIZE; return tpack->pstr; } void tpack_free(TPack tpack){ if( tpack == NULL ) return; if( tpack->phead != NULL ) free( tpack->phead ); if( tpack->pdata != NULL ) free( tpack->pdata ); if( tpack->pstr != NULL ) free( tpack->pstr ); tpack->phead = NULL; tpack->pdata = NULL; tpack->pstr = NULL; //memset( tpack, 0, TPACK_SIZE); free( tpack ); } // Find the corresponding data in the head string char *tpack_head_get_val(char* str, int str_len, char* key, char *val, int val_size) { char* str_end = str + str_len; memset( val, 0, strlen(val) ); char* key_start = memstr( str, str_len, key); if( key_start == NULL ){ return NULL; } char* end = memstr( key_start, ( str_end - key_start ), TPACK_HEAD_LINE_TAG); if( end == NULL ){ // The end of the line must be found return NULL; } char* key_start_i = key_start + strlen(key) + 1; // Start String Position if( (end - key_start_i) < val_size ) val_size = end - key_start_i; strncpy( val, key_start_i, val_size ); val = trim( val ); //printf("key_start and end exist, val_size:%d\n", val_size); return val; } void tpack_parse_head(TPack tpack){ char headVal[TPACK_HEAD_DATA_SIZE]; memset( headVal, 0, TPACK_HEAD_DATA_SIZE ); tpack_head_get_val( tpack->phead, tpack->phead_len, "Form", headVal, TPACK_HEAD_DATA_SIZE); memcpy( tpack->form, headVal, strlen(headVal) ); memset( headVal, 0, TPACK_HEAD_DATA_SIZE ); tpack_head_get_val( tpack->phead, tpack->phead_len, "Socket-Clint", headVal, TPACK_HEAD_DATA_SIZE); tpack->sock_cli = atoi( headVal ); memset( headVal, 0, TPACK_HEAD_DATA_SIZE ); tpack_head_get_val( tpack->phead, tpack->phead_len, "Data-Size", headVal, TPACK_HEAD_DATA_SIZE); tpack->h_data_len = atoi( headVal ); return; } // If you find a return TPack tpack_parse(char* str, uint str_len, char **end) { // Find the terminator through the string char* str_end = str + str_len; // The End of Data char* head_start = str; char* data_start = str; char* head_tag = memstr( str, str_len, TPACK_HEAD_TAG ); // End Marker char* data_tag = memstr( str, str_len, TPACK_DATA_TAG ); // End Marker if( head_tag == NULL ){ printf("TPACK unpack failed,head_tag is NULL\n"); return NULL; } else if( data_tag == NULL ){ printf("TPACK unpack failed,data_tag is NULL\n"); return NULL; } else if( data_tag < head_tag ) { // Reason 1: Leave unprocessed data_tag printf("TPACK unpack failed,data_tag < head_tag error, Left untreated data_tag\n"); // Set head_start to remove the location of the remaining data head_start = data_tag + TPACK_DATA_TAG_SIZE; // Search for data_tag in str again. head-start requires str data_tag = memstr( head_start, ( str_end - head_start), TPACK_DATA_TAG ); if( data_tag == NULL ) printf("TPACK unpack failed,data_tag is NULL (2) \n"); return NULL; } data_start = head_tag + TPACK_HEAD_TAG_SIZE; // Initialize an empty TPack message TPack Tpack = tpack_new( TPACK_CMD_EMPTY, "", 0, "", 0 ); // The size of the bytes between the two pointers that you want to subtract is the size of the bytes found in the header and content area. Tpack->phead_len = head_tag - str; Tpack->pdata_len = data_tag - data_start; memcpy( Tpack->phead, head_start, Tpack->phead_len ); memcpy( Tpack->pdata, data_start, Tpack->pdata_len ); // Parsing head tpack_parse_head( Tpack ); *end = data_tag + TPACK_DATA_TAG_SIZE; // Returns the end tag location return Tpack; }
send contract
// TPACK:: Packing TPack tpack = tpack_new( TPACK_CMD_SEND, TPACK_FORM_SERVER, sock, recv_buf, recvSizeOk ); tpack_tostr( tpack ); //Send TPACK - > PSTR tpack->pstr, tpack->pstr_len tpack_free( tpack );
recv receives the processing, receives the buffer in a loop, and then tries to unpack, and continues to receive until the unpacking succeeds or exceeds the buffer size.
When the buffer size exceeds, the maximum memory that can be put is added to the buffer. If the garbage data can not be parsed, it is closed directly.
// TPACK:: Unpack char* tpack_data_end; // After the parsing is successful, the end data location, including the terminator TPack tpack = tpack_parse( link->recvCache, link->recvLen, &tpack_data_end ); if( tpack == NULL ){ // Failed unpacking, continue receiving printf("target_in_thr: tpack parse failed, wait next recv\n"); set_event_et( link->epoll_fd, EPOLLIN, link->sock ); return NULL; } // TPACK:: The buffer moves forward and clears directly if the tail is equal. int move_len = (link->recvCache + link->recvLen) - tpack_data_end; if( move_len == 0 ){ memset( link->recvCache, 0, TPACK_CACHE_SIZE ); link->recvLen = 0; printf("target_in_thr: recvCache memset\n"); } else { int move_size = tpack_data_end - link->recvCache; // End minus pointer is length memmove( link->recvCache, tpack_data_end, move_size ); link->recvLen = move_size; printf("target_in_thr: recvCache move forward, recvCache: %p, data_end: %p, move size: %d\n", link->recvCache, tpack_data_end, move_size); } //This code does not address processing beyond buffer size.
This is one way I can solve this problem. I hope to get some optimum advice. There are many tpack problems, especially when parsing buffer data.