IP数据报,其可变部分可变是如何实现的?
假设我们在网络通信过程中使用的数据缓冲区,缓冲区包括一个num, size和data字段,分别标识数据的块号,长度和传输的数据,我们设计思路如下:
- 定长数据缓冲区,设置一个足够大小MAXSIZE的数据缓冲区。
- 设置一个指向实际数据的指针,每次使用时,按照数据的长度动态的开辟数据缓冲区的空间。我们从实际场景中应用来考虑他们的优劣,主要考虑点有:缓冲区空间的开辟,释放和访问.
1 定长包:
#define MAX_SIZE 4096 //4K
typedef struct data_buffer
{
int num;
int size;
char data[MAX_SIZE];//该结构体变量大小应该等于4K,使得能将结构体变量数据一次导入内存,不需要调动2次(两个页),且需要储存在硬盘时也不需要两个页来存储
}data_buffer;
//sizeof(int)+sizeof(size)+sizeof(char)*MAXSIZE;
使用定长数组作为数据缓冲区,为了避免造成缓冲区溢出,数组设计是大开小用,而实际使用过程中,达到MAXSIZE长度的数据很少,那么多数情况下,缓冲区的大部分空间都浪费了,也会造成不必要的流量浪费。
但是使用过程很简单,数据空间的开辟和释放简单,无需程序员考虑额外的操作。
2 指针数据包
如果你将上面的长度为MAXSIZE的定长数组换为指针,每次使用时动态的开辟CURSIZE 大小的空间,那么免造成 MAXSIZE - CURSIZE空间的浪费,只浪费了一个指针域的空间。而申请的堆空间相对于栈空间来说大得多得多。
//#define MAX_SIZE 4096 //4K
typedef struct data_buffer
{
int num;
int size;
char * data;
}data_buffer;
//sizeof(int)+sizeof(size)+sizeof(char *);
//但需要申请堆空间和释放
int main()
{
data_buffer * pbuff = (data_buffer *)malloc(sizeof(data_buffer));
if (pbuff == NULL)
{
exit(EXIT_FAILURE)
}
pbuff->size = CURSIZE;//假设CURSIZE为发送数据长度
pbuff->data = (char *)malloc(sizeof(char )*CURSIZE);
if (pbuff->data == NULL)
{
exit(EXIT_FAILURE)
}
free(pbuff->data);
free(pbuff);
pbuff = NULL;
}
使用指针结果作为缓冲区,只多使用了一个指针大小的空间,无需使用MAXSIZE 长度的数组,不会造成空间的大量浪费。但那是开辟空间时,需要额外开辟数据域的空间,施放时候也需要显示释放数据域的空间,但是实际使用过程中,往往在函数中开辟空间,然后返回给使用者指向 struct point_buffer 的指针,这时候我们并不能假定使用者了解我们开辟的细节,并按照约定的操作释放空间,因此使用起来多有不便,甚至造成内存泄漏。
3 变长数据缓冲区
定长数组使用方便,但是却浪费空间。指针形式只多使用了一个指针的空间,不会造成大量空间分浪费,但是使用起来需要多次分配,多次释放,那么有没有一种实现方式既不浪费空间,又使用方便的呢?
#define MAX_SIZE 4096 //4K
typedef struct data_buffer
{
int num;
int size;
char data[];
}data_buffer;
//sizeof(int)+sizeof(size)
//使用时,只需要开辟一次空间即可
int main()
{
int n = strlen("sqhlll") + 1;
data_buffer * pbuff = (data_buffer *)malloc(sizeof(data_buffer)+n);
if (pbuff == NULL)
{
exit(EXIT_FAILURE);
}
pbuff->num = 1;
pbuff->size = n;
memcpy(pbuff->data, "sqhlll", n);
free(pbuff);
pbuff = NULL;
return 0;
}