メモリツールBufferの実現を忘れないでください

JavaまたはNettyフレームワークには、それ自体でカプセル化されたByteBuffer構造があります。これは、アプリケーション層データをバイト配列に変換し、最終的にネットワーク経由で送信するために使用されます。Javaに精通している学生は、これらのAPIに精通している可能性があります。この記事の目的は、NettyのByteBufferを参照して、C / C ++プロジェクトでのメモリアプリケーションとメンテナンスのための同様の構造をカプセル化することです。


0、構造定義

     C / C ++言語の場合、これらはすべてポインターであるため、この情報を格納するための構造体が必要です。ここで、total_sizeは現在のバッファー容量を表します。

//データバッファstructbuffer {char * data; //実際のバッファポインタintreadIndex; //バッファ読み取り位置intwriteIndex; //バッファ書き込み位置inttotal_size; //合計サイズ};

1.メモリの割り当て/解放

     buffer_alloc関数を使用してメモリのブロックを申請できます。ここでは、パラメータ構造のない関数を改善し、デフォルトで8192バイトを適用できます。また、指定されたサイズのメモリに適用するためのパラメータ構築関数も提供します。C / C ++言語にはガベージコレクションメカニズムがないため、ヒープメモリを手動で適用して解放する必要があります。たとえば、次のbuffer_release関数は、要求されたメモリを解放し、最後にバッファ構造を解放します。

#define INIT_BUFFER_SIZE 8192 struct buffer *buffer_alloc() { //无参构造      return buffer_alloc(INIT_BUFFER_SIZE);}
struct buffer *buffer_alloc(int Capacity)//有参构造{    if(Capacity<=0) return NULL;    struct buffer *buffer1 = malloc(sizeof(struct buffer));    if (!buffer1)            return NULL;    buffer1->data = malloc(Capacity);    buffer1->total_size = Capacity;    buffer1->readIndex = 0;    buffer1->writeIndex = 0;    return buffer1;}
void buffer_release(struct buffer *buffer1) {    free(buffer1->data);    free(buffer1);}//辅助函数int buffer_writeable_size(struct buffer *buffer) {    return buffer->total_size - buffer->writeIndex;}//可读字节数int buffer_readable_size(struct buffer *buffer) {    return buffer->writeIndex - buffer->readIndex;}


2.読み取りおよび書き込み操作

    ネットワークフレームワークでは、通常、バイトの書き込み、バイト文字列のコピー、短整数やプラスチックデータの書き込みなどを行います。ここでは、書き込み時にバイト変換を実行する必要があります。外の世界に詳細を提供することなく、それらを統一された方法でカプセル化できます。
    次のbuffer_append関数を使用して、バイトのセグメントをバッファに書き込みます。最初に、バッファ内のメモリが十分かどうかを確認します。十分でない場合は、make_buffer_more関数を呼び出して展開する必要があります。

void make_buffer_more(struct buffer * buffer、int size){if(buffer_writeable_size(buffer)> = size){return; } //如果当前バッファ int i; for(i = 0; i <読み取り可能; i ++){memcpy(buffer-> data + i、buffer-> data + buffer-> readIndex + i、1); } buffer-> readIndex = 0; buffer-> writeIndex =読み取り可能; } else {//内存不够了、扩大缓冲区void * tmp = realloc(buffer-> data、buffer-> total_size + size); if(tmp == NULL){return; } buffer-> data = tmp; buffer-> total_size + =サイズ; }} int buffer_append(struct buffer * buffer、void * data、int size){if(data!= NULL){make_buffer_more(buffer、

     同様に、CHAR、USHORT、INTの読み取りと書き込みの関数も簡単に実装できます。

int buffer_write_char(struct buffer *buffer, char data) {    make_buffer_more(buffer, 1);    //拷贝数据到可写空间中    buffer->data[buffer->writeIndex++] = data;    return 0;}
int buffer_write_ushort(struct buffer *buffer, ushort data) {    make_buffer_more(buffer, 2);    //拷贝数据到可写空间中    ushort ndata = htons(data);//字节序转换    buffer->data[buffer->writeIndex] = data;    memcpy(&(buffer->data[buffer->writeIndex]),ndata,sizeof(data));    buffer->writeIndex+=2;//移动2个字节    return 0;} //省略其他函数


3.ユースケース

        私たちがよく使用するネットワークのエンコードとデコードの方法は、長さドメインに基づいています。たとえば、この形式<msg_len> <msg_id> {content}を使用します。通常、msg_lenは2バイトで、次のコンテンツの長さを表します。msg_idは2バイトで、アプリケーション層メッセージのタイプを区別するために使用されます。最後に、データ本文のコンテンツ。アプリケーション層でハートビートパケットを送信するためのリファレンスコードを見てみましょう。

void write_polling(){// <msg_len> <msg_id> BYTEバッファ[16]; memset(buffer、0、sizeof(buffer)); BYTE * pSend =バッファ; *(USHORT *)pSend = htons(2); // msg_len pSend + = 2; *(USHORT *)pSend = htons(0x1001); // msg_id pSend + = 2; SendOut(buffer、pSend-buffer); // MgSO络ρか去}
        上記のコードは、ポインタの移動と計算を含みます。メッセージ本文がより複雑な場合、コードを管理する人は、ポインタの移動を忘れるなどのエラーが発生しやすくなります。では、パッケージ化されたバッファを使用してそれを実現するにはどうすればよいでしょうか。
void write_polling(){// <msg_len> <msg_id> struct buffer * ByteBuffer = buffer_alloc(16); buffer_write_ushort(ByteBuffer、2); // len buffer_write_ushort(ByteBuffer、0x1001); // id SendOut(ByteBuffer-> data + ByteBuffer-> readIndex、//円他封装buffer_読み取り可能サイズ(ByteBuffer)); //释放...}

       対照的に、write_polling関数を見てください。次の方法はより直感的です。アプリケーション層でのポインターの移動はなく、内部の詳細は公開されません。


おすすめ

転載: blog.51cto.com/15060546/2641108