C语言重写网络发送/接收封包
本文贴出用C语言重写的网络封包,主体设计思路前文已经介绍过,就是尽可能的共享缓存,减少不必要的内存拷贝.
其次,封包主要是为了适合网络游戏等有固定模式的,面向字节流的协议,所以并不适合用于http类协议的处理.
最后,代码没有做优化,内存的分配都是经由calloc,后面会用内存池代替。
项目地址:https://github.com/sniperHW/KendyNet/tree/master/IOCP
rpacket从网络中接收到的数据封包:
#ifndef _RPACKET_H #define _RPACKET_H #include "buffer.h" typedef struct rpacket { unsigned long cmd; unsigned long len; //包长 unsigned long rpos; //读下标 unsigned long data_remain; unsigned long binbufpos; unsigned long begin_pos; buffer_t binbuf; //用于存放跨越buffer_t边界数据的buffer_t buffer_t buf; //存放此数据包内容的buffer_t链表 buffer_t readbuf; //当前rpos所在的buffer_t }*rpacket_t; struct wpacket; rpacket_t rpacket_create(buffer_t,unsigned long pos); rpacket_t rpacket_create_by_wpacket(struct wpacket*);//通过wpacket构造 void rpacket_destroy(rpacket_t*); //数据读取接口 unsigned long rpacket_len(rpacket_t); unsigned long rpacket_read_cmd(rpacket_t); unsigned long rpacket_data_remain(rpacket_t); unsigned char rpacket_read_char(rpacket_t); unsigned short rpacket_read_short(rpacket_t); unsigned long rpacket_read_long(rpacket_t); double rpacket_read_double(rpacket_t); const char* rpacket_read_string(rpacket_t); const void* rpacket_read_binary(rpacket_t,unsigned long *len); #endif
#include "rpacket.h" #include "wpacket.h" #include <stdlib.h> #include <string.h> rpacket_t rpacket_create(buffer_t b,unsigned long pos/*数据在b中的起始下标*/) { rpacket_t r = calloc(1,sizeof(*r)); r->binbuf = 0; r->binbufpos = 0; r->buf = buffer_acquire(0,b); r->readbuf = buffer_acquire(0,b); r->len = *(unsigned long*)(&(b->buf[pos])); r->data_remain = r->len; r->rpos = pos + sizeof(r->len); r->begin_pos = pos; return r; } rpacket_t rpacket_create_by_wpacket(struct wpacket *w) { rpacket_t r = calloc(1,sizeof(*r)); r->binbuf = 0; r->binbufpos = 0; r->buf = buffer_acquire(0,w->buf); r->readbuf = buffer_acquire(0,w->buf); //这里的len只记录构造时wpacket的len,之后wpacket的写入不会影响到rpacket的len r->len = *(unsigned long*)(&(w->buf->buf[w->begin_pos])); r->data_remain = r->len; r->rpos = 0 + sizeof(r->len); r->begin_pos = w->begin_pos; return r; } void rpacket_destroy(rpacket_t *r) { //释放所有对buffer_t的引用 buffer_release(&(*r)->buf); buffer_release(&(*r)->readbuf); buffer_release(&(*r)->binbuf); } unsigned long rpacket_read_cmd(rpacket_t r) { return r->cmd; } unsigned long rpacket_len(rpacket_t r) { return r->len; } unsigned long rpacket_data_remain(rpacket_t r) { return r->data_remain; } static int rpacket_read(rpacket_t r,char *out,unsigned long size) { buffer_t _next = 0; if(r->data_remain < size) return -1; while(size>0) { unsigned long copy_size = r->readbuf->size - r->rpos; copy_size = copy_size >= size ? size:copy_size; memcpy(out,r->readbuf->buf + r->rpos,copy_size); size -= copy_size; r->rpos += copy_size; r->data_remain -= copy_size; out += copy_size; if(r->rpos >= r->readbuf->size && r->data_remain) { //当前buffer数据已经被读完,切换到下一个buffer r->rpos = 0; r->readbuf = buffer_acquire(r->readbuf,r->readbuf->next); } } return 0; } unsigned char rpacket_read_char(rpacket_t r) { unsigned char value = 0; rpacket_read(r,(char*)&value,sizeof(value)); return value; } unsigned short rpacket_read_short(rpacket_t r) { unsigned short value = 0; rpacket_read(r,(char*)&value,sizeof(value)); return value; } unsigned long rpacket_read_long(rpacket_t r) { unsigned long value = 0; rpacket_read(r,(char*)&value,sizeof(value)); return value; } double rpacket_read_double(rpacket_t r) { double value = 0; rpacket_read(r,(char*)&value,sizeof(value)); return value; } const char* rpacket_read_string(rpacket_t r) { unsigned long len = 0; return (const char *)rpacket_read_binary(r,&len); } const void* rpacket_read_binary(rpacket_t r,unsigned long *len) { void *addr = 0; unsigned long size = rpacket_read_long(r); *len = size; if(r->data_remain < size) return addr; if(r->buf->size - r->rpos >= size) { addr = &r->buf[r->rpos]; r->rpos += size; r->data_remain -= size; if(r->rpos >= r->readbuf->size && r->data_remain) { //当前buffer数据已经被读完,切换到下一个buffer r->rpos = 0; r->readbuf = buffer_acquire(r->readbuf,r->readbuf->next); } } else { //数据跨越了buffer边界,创建binbuf,将数据拷贝到binbuf中 if(!r->binbuf) { r->binbufpos = 0; r->binbuf = buffer_create_and_acquire(0,r->len); } addr = r->binbuf->buf + r->binbufpos; while(size) { unsigned long copy_size = r->readbuf->size - r->rpos; copy_size = copy_size >= size ? size:copy_size; memcpy(r->binbuf->buf + r->binbufpos,r->readbuf->buf + r->rpos,copy_size); size -= copy_size; r->rpos += copy_size; r->data_remain -= copy_size; r->binbufpos += copy_size; if(r->rpos >= r->readbuf->size && r->data_remain) { //当前buffer数据已经被读完,切换到下一个buffer r->rpos = 0; r->readbuf = buffer_acquire(r->readbuf,r->readbuf->next); } } } return addr; }
wpacket发送数据封包:
#ifndef _WPACKET_H #define _WPACKET_H #include "buffer.h" typedef struct wpacket { unsigned long *len; buffer_t buf; buffer_t writebuf; unsigned long wpos; unsigned char factor; unsigned long begin_pos; }*wpacket_t; struct rpacket; typedef struct { buffer_t buf; unsigned long wpos; }write_pos; wpacket_t wpacket_create(unsigned long size); wpacket_t wpacket_create_by_rpacket(struct rpacket*);//通过rpacket构造 void wpacket_destroy(wpacket_t*); write_pos wpacket_get_writepos(wpacket_t); void wpacket_write_char(wpacket_t,unsigned char); void wpacket_write_short(wpacket_t,unsigned short); void wpacket_write_long(wpacket_t,unsigned long); void wpacket_write_double(wpacket_t,double); void wpacket_rewrite_char(write_pos*,unsigned char); void wpacket_rewrite_short(write_pos*,unsigned short); void wpacket_rewrite_long(write_pos*,unsigned long); void wpacket_rewrite_double(write_pos*,double); //不提供对非定长数据的rewrite void wpacket_write_string(wpacket_t,const char*); void wpacket_write_binary(wpacket_t,const void*,unsigned long); #endif
#include "wpacket.h" #include <stdlib.h> #include <string.h> #include <assert.h> #include "rpacket.h" static int is_pow_of_2(unsigned long size) { return !(size&(size-1)); } static unsigned char GetK(unsigned long size) { unsigned char k = 0; if(!is_pow_of_2(size)) { size = (size << 1); } //除最高为1位以外,其它位全部清0 while(size > 1) { k++; size = size >> 1; } return k; } wpacket_t wpacket_create(unsigned long size) { unsigned char k = GetK(size); wpacket_t w; size = 1 << k; w = calloc(1,sizeof(*w)); w->factor = k; w->wpos = sizeof(w->len); w->buf = buffer_create_and_acquire(0,size); w->writebuf = buffer_acquire(0,w->buf); w->len = (unsigned long*)w->buf->buf; *(w->len) = 0; w->buf->size = sizeof(w->len); w->begin_pos = 0; return w; } wpacket_t wpacket_create_by_rpacket(struct rpacket *r) { wpacket_t w = calloc(1,sizeof(*w)); w->factor = 0; w->writebuf = 0; w->begin_pos = r->begin_pos; w->buf = buffer_acquire(0,r->buf); w->len = (unsigned long*)(r->buf->buf + r->begin_pos); w->wpos = 0; return w; } write_pos wpacket_get_writepos(wpacket_t w) { write_pos wp = {w->writebuf,w->wpos}; return wp; } void wpacket_destroy(wpacket_t *w) { buffer_release(&(*w)->buf); buffer_release(&(*w)->writebuf); free(*w); *w = 0; } static void wpacket_expand(wpacket_t w) { unsigned long size; w->factor <<= 1; size = 1 << w->factor; w->writebuf->next = buffer_create_and_acquire(0,size); w->writebuf = buffer_acquire(w->writebuf,w->writebuf->next); w->wpos = 0; } static void wpacket_copy(wpacket_t w,buffer_t buf) { char *ptr = buf->buf; buffer_t tmp_buf = w->buf; unsigned long copy_size; while(tmp_buf) { copy_size = tmp_buf->size - w->wpos; memcpy(ptr,tmp_buf->buf,copy_size); ptr += copy_size; w->wpos = 0; tmp_buf = tmp_buf->next; } } static void wpacket_write(wpacket_t w,char *addr,unsigned long size) { char *ptr = addr; unsigned long copy_size; buffer_t tmp; unsigned char k; if(!w->writebuf) { /*wpacket是由rpacket构造的,这里执行写时拷贝, * 执行完后wpacket和构造时传入的rpacket不再共享buffer */ k = GetK(*w->len); w->factor = k; tmp = buffer_create_and_acquire(0,1 << k); wpacket_copy(w,tmp); w->begin_pos = 0; w->len = (unsigned long*)tmp->buf; w->wpos = sizeof(*w->len); w->buf = buffer_acquire(w->buf,tmp); w->writebuf = buffer_acquire(w->writebuf,w->buf); } while(size) { copy_size = w->buf->capacity - w->wpos; if(copy_size == 0) { wpacket_expand(w);//空间不足,扩展 copy_size = w->buf->capacity - w->wpos; } copy_size = copy_size > size ? size:copy_size; memcpy(w->writebuf->buf + w->wpos,ptr,copy_size); w->writebuf->size += copy_size; (*w->len) += copy_size; w->wpos += copy_size; ptr += copy_size; size -= copy_size; } } void wpacket_write_char(wpacket_t w,unsigned char value) { wpacket_write(w,(char*)&value,sizeof(value)); } void wpacket_write_short(wpacket_t w,unsigned short value) { wpacket_write(w,(char*)&value,sizeof(value)); } void wpacket_write_long(wpacket_t w,unsigned long value) { wpacket_write(w,(char*)&value,sizeof(value)); } void wpacket_write_double(wpacket_t w ,double value) { wpacket_write(w,(char*)&value,sizeof(value)); } static void wpacket_rewrite(write_pos *wp,char *addr,unsigned long size) { char *ptr = addr; unsigned long copy_size; unsigned long pos = wp->wpos; while(size) { copy_size = wp->buf->capacity - pos; copy_size = copy_size > size ? size:copy_size; memcpy(wp->buf->buf + pos,ptr,copy_size); ptr += copy_size; size -= copy_size; pos += copy_size; if(size && pos >= wp->buf->capacity) { assert(wp->buf->next); wp->buf = wp->buf->next; pos = 0; } } } void wpacket_rewrite_char(write_pos *wp,unsigned char value) { wpacket_rewrite(wp,&value,sizeof(value)); } void wpacket_rewrite_short(write_pos *wp,unsigned short value) { wpacket_rewrite(wp,(char*)&value,sizeof(value)); } void wpacket_rewrite_long(write_pos *wp,unsigned long value) { wpacket_rewrite(wp,(char*)&value,sizeof(value)); } void wpacket_rewrite_double(write_pos *wp,double value) { wpacket_rewrite(wp,(char*)&value,sizeof(value)); } void wpacket_write_string(wpacket_t w ,const char *value) { wpacket_write_binary(w,value,strlen(value)+1); } void wpacket_write_binary(wpacket_t w,const void *value,unsigned long size) { assert(value); wpacket_write_long(w,size); wpacket_write(w,(char*)value,size); }
简单的测试代码:
void test1() { wpacket_t w = wpacket_create(12); rpacket_t r,r1; wpacket_t w1 = 0; const char *str; wpacket_write_string(w,"hello kenny"); r = rpacket_create_by_wpacket(w); wpacket_destroy(&w); str = rpacket_read_string(r); printf("str=%s\n",str); w1 = wpacket_create_by_rpacket(r); r1 = rpacket_create_by_wpacket(w1); str = rpacket_read_string(r1); printf("str=%s\n",str); rpacket_destroy(&r); rpacket_destroy(&r1); wpacket_destroy(&w1); } void test2() { wpacket_t w = wpacket_create(12); rpacket_t r; write_pos wp; wpacket_write_long(w,1); wp = wpacket_get_writepos(w); wpacket_write_short(w,2); wpacket_write_string(w,"hello kenny"); wpacket_rewrite_short(&wp,4); r = rpacket_create_by_wpacket(w); printf("%u\n",rpacket_read_long(r)); printf("%u\n",rpacket_read_short(r)); printf("%s\n",rpacket_read_string(r)); rpacket_destroy(&r); wpacket_destroy(&w); }