??xml version="1.0" encoding="utf-8" standalone="yes"?>
]]>
]]>
BOOL为int?
bool为布型
2、长度不?
bool只有一个字?
BOOL长度视实际环境来定,一般可认ؓ?个字?
3、取g?
bool取值false和trueQ是0?的区?
BOOL取值FALSE和TRUEQ是0和非0的区?
二:
bool是标准C++数据cdQ可取值true和false。单独占一个字节,
如果Cbool对象列在一P可能会各占一个bitQ这取决于编译器?
BOOL是微软定义的typedef int BOOL。与bool不同Q它是一个三值逻辑Q?
TRUE/FALSE/ERRORQ返回gؓ>0的整CؓTRUEQ?为FALSEQ?1为ERROR?
Win32 API中很多返回gؓBOOL的函数都是三值逻辑。比如GetMessage().
三:
大BOOL和小bool之间的区别:
1、类型不?
BOOL为int?
bool为布型
2、长度不?
bool只有一个字?
BOOL长度视实际环境来定,一般可认ؓ?个字?
3、取g?
bool取值false和trueQ是0?的区?
BOOL取值FALSE和TRUEQ是0和非0的区?
4、例?
bool x=3; //告警
bool x=1; //正确
BOOL x=3; //正确
BOOL x=3.3; //告警
注:windowsZ兼容问题定义的基变量?
typedef unsigned long DWORD;
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef float FLOAT;
typedef FLOAT *PFLOAT;
typedef BOOL near *PBOOL;
typedef BOOL far *LPBOOL;
typedef BYTE near *PBYTE;
typedef BYTE far *LPBYTE;
typedef int near *PINT;
typedef int far *LPINT;
]]>
]]>
哪些变量会在栈中分配I间Q哪些变量会在堆中分配空?/span>?
---------------------------------------------------------------
1?span style="COLOR: maroon">甌方式
stack:
ql?span style="COLOR: red">自动分配?/span> 例如Q声明在函数中一个局部变?/span> int b; pȝ自动在栈中ؓb开辟空?/span>
heap:
需要程序员自己甌Qƈ指明大小Q在c?/span>malloc函数
?/span>p1 = (char *)malloc(10); //free
?/span>C++中用newq算W?/span> //delete
?/span>p2 = (char *)malloc(10);
但是注意p1?/span>p2本n是在栈中的?/span>
2?span style="COLOR: maroon">甌后系l的响应
栈:只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢?/span>?/span>
堆:首先应该知道操作pȝ有一?span style="COLOR: red">记录I闲内存地址的链?/span>Q当pȝ收到E序的申hQ?/span>
会遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将该结点的I间分配l程序,另外Q对于大多数pȝQ会在这块内存空间中的首地址处记录本ơ分配的大小Q这P代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正好等于申L大小Q系l会自动的将多余的那部分重新攑օI闲链表中?/span>
3?span style="COLOR: maroon">甌大小的限?/span>
栈:?/span>Windows?/span>,栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是pȝ预先规定好的Q在WINDOWS下,栈的大小?/span>
堆:堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地址的,自然是不q箋的,而链表的遍历方向是由低地址向高地址。堆的大受限于计算机系l中有效的虚拟内存。由此可见,堆获得的I间比较灉|Q也比较?/span>?/span>
4?span style="COLOR: maroon">甌效率的比较:
栈由pȝ自动分配Q?span style="COLOR: red">速度较快。但E序员是无法控制的?/span>
堆是?/span>new分配的内?/span>Q一?span style="COLOR: red">速度比较?/span>Q而且Ҏ产生内存片,不过用v来最方便.
另外Q在WINDOWS下,最好的方式是用VirtualAlloc分配内存Q他不是在堆Q也不是在栈是直接在q程的地址I间中保留一快内存,虽然用v来最不方ѝ但是速度快,也最灉|?/span>
5?span style="COLOR: maroon">堆和栈中的存储内?/span>
栈:在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的地址Q然后是函数的各个参敎ͼ在大多数?/span>C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变量。注意静态变量是不入栈的?/span>
当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是dC的下一条指令,E序p点l运行?/span>
堆:一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容有程序员安排?/span>
6?span style="COLOR: maroon">存取效率的比?/span>
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在q行时刻赋值的Q?/span>
?/span>bbbbbbbbbbb是在~译时就定的;
但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?/span>)快?/span>
比如Q?/span>
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度?/span>
static 声明的变量在C语言中有两方?/span>的特征:
1)、变量会被放在程序的全局存储?/span>中,q样可以在下一ơ调用的时候还可以保持原来的赋?/span>。这一Ҏ它与堆栈变量和堆变量的区别?/span>
2)、变量用static告知~译器,自己仅仅在变量的作用范围内可?/span>。这一Ҏ它与全局变量的区别?/span>
Tips:
A.若全局变量仅在单个C文g中访问,则可以将q个变量修改为静态全局变量Q以降低模块间的耦合度;
B.若全局变量仅由单个函数讉KQ则可以这个变量改函数的静态局部变量,以降低模块间的耦合度;
C.设计和用访问动态全局变量、静态全局变量、静态局部变量的函数Ӟ需要考虑重入问题Q?/span>
D.如果我们需要一个可重入的函敎ͼ那么Q我们一定要避免函数中?/span>static变量(q样的函数被UCؓQ带“内部存储?/span>”功能的的函数)
E.函数中必要使用static变量情况:比如当某函数的返回gؓ指针cdӞ则必Lstatic的局部变量的地址作ؓq回|若ؓautocdQ则q回为错指针?/span>
函数前加static使得函数成ؓ静态函?/span>。但此处“static”的含?span style="COLOR: red">不是指存储方?/span>Q而是指对函数?span style="COLOR: red">作用域仅局限于本文?/span>(所以又U内部函?/span>)。用内部函数的好处是:不同的h~写不同的函数时Q不用担心自己定义的函数Q是否会与其它文件中的函数同名?/span>
扩展分析:术语static有着不寻常的历史.起初Q在C中引入关键字static是ؓ了表C退Z个块后仍然存在的局部变量。随后,static?/span>C中有了第二种含义Q用来表CZ能被其它文g讉K的全局变量和函数。ؓ了避免引入新的关键字Q所以仍使用static关键字来表示q第二种含义。最后,C++重用了这个关键字Qƈ赋予它与前面不同的第三种含义Q表C属于一个类而不是属于此cȝM特定对象的变量和函数(?/span>Java中此关键字的含义相同)?/span>
全局变量、静态全局变量、静态局部变量和局部变量的区别
变量可以分ؓQ全局变量、静态全局变量、静态局部变量和局部变量?/span>
?span style="COLOR: red">存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区?/span>Q局部变量存攑֜内存?span style="COLOR: red">栈区?/span>
?span style="COLOR: red">作用?/span>分,全局变量在整个工E文件内都有效;静态全局变量只在定义它的文g内有效;静态局部变量只在定义它的函数内有效Q只是程序仅分配一ơ内存,函数q回后,该变量不会消失;局部变量在定义它的函数内有效,但是函数q回后失?/span>?/span>
全局变量(外部变量)的说明之前再冠以static 构成了静态的全局变量。全局变量本n是静态存储方式, 静态全局变量当然也是静态存储方式?/span> q两者在存储方式上ƈ无不同。这两者的区别虽在于非静态全局变量的作用域是整个源E序Q?/span> 当一个源E序由多个源文gl成Ӟ非静态的全局变量在各个源文g中都是有效的?/span> 而静态全局变量则限制了其作用域Q?/span> 卛_在定义该变量的源文g内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文g内,只能源文件内的函数公用, 因此可以避免在其它源文g中引起错误?/span>
从以上分析可以看出, 把局部变量改变ؓ静态变量后是改变了它的存储方式x变了它的生存?/span>。把全局变量改变为静态变量后是改变了它的作用?/span>Q?/span> 限制了它的用范围?/span>
static函数与普通函C用域不同?span style="COLOR: red">仅在本文件。只在当前源文g中用的函数应该说明为内部函?/span>(static)Q内部函数应该在当前源文件中说明和定义。对于可在当前源文g以外使用的函敎ͼ应该在一个头文g中说明,要用这些函数的源文件要包含q个头文?/span>
static全局变量与普通的全局变量有什么区别:static全局变量只初始化一ơ,防止在其他文件单元中被引?/span>;
static局部变量和普通局部变量有什么区别:static局部变量只被初始化一ơ,下一ơ依据上一ơ结果|
static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中l持一份拷?/span>
全局变量和静态变量如果没有手工初始化Q?span style="COLOR: red">则由~译器初始化?/span>0。局部变量的g可知?/span>
你会用sizeof吗?Qvc)
本文主要包括二个部分Q第一部分重点介绍在VC中,怎么样采用sizeof来求l构的大,以及Ҏ出现的问题,q给决问题的ҎQ第二部分ȝ出VC中sizeof的主要用法?br> 1?sizeof应用在结构上的情?br> L下面的结构: struct MyStruct { double dda1; char dda; int type }; 对结构MyStruct采用sizeof会出C么结果呢Qsizeof(MyStruct)为多呢Q也怽会这hQ?br> sizeof(MyStruct)=sizeof(double)+sizeof(char)+sizeof(int)=13 但是当在VC中测试上面结构的大小Ӟ你会发现sizeof(MyStruct)?6。你知道Z么在VC中会得出q样一个结果吗Q?br> 其实Q这是VC对变量存储的一个特D处理。ؓ了提高CPU的存储速度QVC对一些变量的起始地址做了“寚w”处理。在默认情况下,VC规定各成员变量存攄起始地址相对于结构的起始地址的偏U量必须变量的类型所占用的字节数的倍数。下面列出常用类型的寚w方式(vc6.0,32位系l??br> cd 寚w方式Q变量存攄起始地址相对于结构的起始地址的偏U量Q?br> Char 偏移量必Mؓsizeof(char)?的倍数 int 偏移量必Mؓsizeof(int)?的倍数 float 偏移量必Mؓsizeof(float)?的倍数 double 偏移量必Mؓsizeof(double)?的倍数 Short 偏移量必Mؓsizeof(short)?的倍数 各成员变量在存放的时候根据在l构中出现的序依次甌I间Q同时按照上面的寚w方式调整位置Q空~的字节VC会自动填充。同时VCZ保l构的大ؓl构的字节边界数Q即该结构中占用最大空间的cd所占用的字节数Q的倍数Q所以在为最后一个成员变量申L间后Q还会根据需要自动填充空~的字节?br> 下面用前面的例子来说明VC到底怎么h存放l构的?br> struct MyStruct { double dda1; char dda; int type }Q?br> Z面的l构分配I间的时候,VCҎ成员变量出现的顺序和寚w方式Q先为第一个成员dda1分配I间Q其起始地址跟结构的起始地址相同Q刚好偏U量0刚好为sizeof(double)的倍数Q,该成员变量占用sizeof(double)=8个字节;接下来ؓW二个成员dda分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q是sizeof(char)的倍数Q所以把dda存放在偏U量?的地Ҏ_齐方式,该成员变量占用sizeof(char)=1个字节;接下来ؓW三个成员type分配I间Q这时下一个可以分配的地址对于l构的v始地址的偏U量?Q不是sizeof(int)=4的倍数Qؓ了满_齐方式对偏移量的U束问题QVC自动填充3个字节(q三个字节没有放什么东西)Q这时下一个可以分配的地址对于l构的v始地址的偏U量?2Q刚好是sizeof(int)=4的倍数Q所以把type存放在偏U量?2的地方,该成员变量占用sizeof(int)=4个字节;q时整个l构的成员变量已l都分配了空_ȝ占用的空间大ؓQ?+1+3+4=16Q刚好ؓl构的字节边界数Q即l构中占用最大空间的cd所占用的字节数sizeof(double)=8Q的倍数Q所以没有空~的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4=16Q其中有3个字节是VC自动填充的,没有放Q何有意义的东ѝ?br> 下面再D个例子,交换一下上面的MyStruct的成员变量的位置Q它变成下面的情况Q?br> struct MyStruct { char dda; double dda1; int type }Q?br> q个l构占用的空间ؓ多大呢?在VC6.0环境下,可以得到sizeof(MyStruc)?4。结合上面提到的分配I间的一些原则,分析下VC怎么样ؓ上面的结构分配空间的。(单说明) struct MyStruct { char dda;//偏移量ؓ0Q满_齐方式,dda占用1个字节; double dda1;//下一个可用的地址的偏U量?Q不是sizeof(double)=8 //的倍数Q需要补?个字节才能偏移量变?Q满_?br> //方式Q,因此VC自动填充7个字节,dda1存放在偏U量? //的地址上,它占?个字节?br> int typeQ?/下一个可用的地址的偏U量?6Q是sizeof(int)=4的?br> //敎ͼ满int的对齐方式,所以不需要VC自动填充Qtype?br> //攑֜偏移量ؓ16的地址上,它占?个字节?br> }Q?/所有成员变量都分配了空_I间ȝ大小?+7+8+4=20Q不是结?br> //的节边界敎ͼ即结构中占用最大空间的cd所占用的字节数sizeof //(double)=8Q的倍数Q所以需要填?个字节,以满结构的大小?br> //sizeof(double)=8的倍数?br> 所以该l构ȝ大小为:sizeof(MyStruc)?+7+8+4+4=24。其中ȝ?+4=11个字节是VC自动填充的,没有放Q何有意义的东ѝ?br> VC对结构的存储的特D处理确实提高CPU存储变量的速度Q但是有时候也带来了一些麻烦,我们也屏蔽掉变量默认的对齐方式,自己可以讑֮变量的对齐方式?br> VC中提供了#pragma pack(n)来设定变量以n字节寚w方式。n字节寚w是说变量存攄起始地址的偏U量有两U情况:W一、如果n大于{于该变量所占用的字节数Q那么偏U量必须满默认的对齐方式,W二、如果n于该变量的cd所占用的字节数Q那么偏U量为n的倍数Q不用满默认的寚w方式。结构的d也有个U束条gQ分下面两种情况Q如果n大于所有成员变量类型所占用的字节数Q那么结构的d必Mؓ占用I间最大的变量占用的空间数的倍数Q?br> 否则必须为n的倍数。下面D例说明其用法?br> #pragma pack(push) //保存寚w状?br> #pragma pack(4)//讑֮?字节寚w struct test { char m1; double m4; int m3; }; #pragma pack(pop)//恢复寚w状?br> 以上l构的大ؓ16Q下面分析其存储情况Q首先ؓm1分配I间Q其偏移量ؓ0Q满x们自p定的寚w方式Q?字节寚wQ,m1占用1个字节。接着开始ؓm4分配I间Q这时其偏移量ؓ1Q需要补?个字节,q样使偏U量满为n=4的倍数Q因为sizeof(double)大于nQ?m4占用8个字节。接着为m3分配I间Q这时其偏移量ؓ12Q满ؓ4的倍数Qm3占用4个字节。这时已lؓ所有成员变量分配了I间Q共分配?6个字节,满为n的倍数。如果把上面?pragma pack(4)改ؓ#pragma pack(16)Q那么我们可以得到结构的大小?4。(误者自己分析) 2?sizeof用法ȝ 在VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个ȝ?br> AQ?参数为数据类型或者ؓ一般变量。例如sizeof(int),sizeof(long){等。这U情况要注意的是不同pȝpȝ或者不同编译器得到的结果可能是不同的。例如intcd?6位系l中?个字节,?2位系l中?个字节?br> BQ?参数为数l或指针。下面D例说? int a[50]; //sizeof(a)=4*50=200; 求数l所占的I间大小 int *a=new int[50];// sizeof(a)=4; aZ个指针,sizeof(a)是求指针 //的大??2位系l中Q当然是?个字节?br> CQ?参数为结构或cRSizeof应用在类和结构的处理情况是相同的。但有两炚w要注意,W一、结构或者类中的静态成员不对结构或者类的大生媄响,因ؓ静态变量的存储位置与结构或者类的实例地址无关?br> W二、没有成员变量的l构或类的大ؓ1Q因为必M证结构或cȝ每一 个实例在内存中都有唯一的地址?br> 下面举例说明Q?br> Class Test{int a;static double c};//sizeof(Test)=4. Test *s;//sizeof(s)=4,sZ个指针?br> Class test1{ };//sizeof(test1)=1; DQ?参数为其他。下面D例说明?br> int func(char s[5]); { cout< //数的参数在传递的时候系l处理ؓ一个指针,所 //以sizeof(s)实际上ؓ求指针的大小?br> return 1; } sizeof(func(“1234”))=4//因ؓfunc的返回类型ؓintQ所以相当于 //求sizeof(int). 以上为sizeof的基本用法,在实际的使用中要注意分析VC的分配变量的分配{略Q这L话可以避免一些错误?/td> |
每个cd在编译时都会军_自己的实例需要多字节。在~译后,该类型的所有对象占有的I间是一LQ不会发生变化。因此,我们可以用sizeof来计一个类型或者该cd的某个实例来得到寸信息。下面的代码是等L
无论我们用iValq是intQ上面的表达式都会返回intcd的尺寸(当然如前所_iVal的尺寸和其类型尺寸永q是一L)?/p>
不熟悉sizeof的朋友往往会在处理指针时弄错概c考虑下面代码Q?/p>
在很多h心目中,指针和数l是{h的,但是事实严格hq不如此。上面的代码׃q回不同的结果?/p>
对于iArrayQ它的类型是int[10]Q是一个数l,sizeof计算其尺寸时Q知道它包含10个元素,每个元素都时个整型,因此q回40。而对于pQ它的类型是int*Q指针的寸永远?Q因此结果就?。sizeof不会也不可能知道p实际指向10个元素的数组?/p>
出现q个问题的原因有两个Q?. sizeof是在~译时计的Q而new int[10]指向的数l是在运行时创徏的,也就是说当sizeof(p)计算Ӟpȝq不知道p会指向多个int元素Q自然也不可能知道它指向的数l占有多字节?. sizeof计算的是p自己的类型所占据的空_而不是p指向的对象所占据的空_可以_p自己占据4个字节,而p指向的空间占40字节?/p>
在这U概念下Q我们是不是可以通过sizeof(*p)来得?0呢?很不q,不行Q原因是p的类型是int*Q?p的类型是intQ因此无法得到其是一个数l的事实?/p>
实际上,q个寸信息是个q行时数据,作ؓC/C++语言而言Q是无从知道q个信息的(因ؓC/C++指针不包含这U信息)Q要得到它,唯一的办法是指望操作pȝ在运行时中提供。在VC中,我们可以通过_msize得到?/p>
2. 寚w问题
我们在访问内存时Q如果地址是按4字节寚wQ则讉K效率会高很多。这个问题的原因在于讉K内存的硬件电路。一般情况下Q地址ȝL按照寚w后的地址来访问。例如你惛_?x00000001开始的4字节内容Q系l首先需要以0x00000000?字节Q然后从中取?字节Q然后在?x00000004作ؓ开始地址Q获得下一个四字节Q在从中得到W一个字节,两次l合Z惛_到的内容。但是如果地址一开始就是对齐到0x00000000Q则pȝ只要一ơ读写即可?/p>
Z性能考虑Q编译器会对l构q行寚w处理。考虑下面的结?/p>
直观的讲Q这个结构的寸是sizeof(char)+sizeof(int)Q?,但是在实际编译下Q这个结构尺寸缺省是8Q因为第二个域ivalue会被寚w到第四个字节?/p>
在VC中,我们可以用pack预处理指令来止寚w调整。例?下面代码得结构尺寸更加紧凑,不会出现寚w?字节问题Q?/p>
对于q个pack指o的含义,大家可以查询MSDN。请注意Q除非你觉得必须q样Q不要轻易做q样的调_因ؓq将降低E序性能。目前比较常见的用法是:1. q个l构需要被直接写入文g 2. q个l构需要通过|络传给其他E序?/p>
注意Q字节对齐是~译时决定的Q一旦决定不会再改变Q因此即使有寚w的因素在Q也不会出现一个结构在q行时尺寸发生变化的情况出现?/p>
IP协议QInternet ProtocolQ是|络层协议,用在因特|上QTCPQUDPQICMPQIGMP数据都是按照IP数据格式发送得。IP协议提供的是不可靠无q接得服务。IP数据包由一个头部和一个正文部分构成。正文主要是传输的数据,我们主要来理解头部数据,可以从其理解到IP协议。
IP数据包头部格式(RFC791Q?/strong>
Example Internet Datagram Header
上面的就是IP数据的头部格式,q里大概Cl一下。
IP头部?0字节的固定长度和一个可选Q意长度部分构成,以大D늂机次序传送,从左?叟뀂
TCP协议
TCP协议QTRANSMISSION CONTROL PROTOCOLQ是传输层协议,为应用层提供服务Q和UDP不同的是QTCP协议提供的可靠的面向q接的服务。在RFC793中是基本的TCP描述。关于TCP协议的头部格式内容的说明Q
TCP Header FORMat
TCP Header FORMat
跟IP头部差不多,基本的长度也?0字节。TCP数据包是包含在一个IP数据报文中的。
好了Q简单介l到此ؓ止。来看看我捕L例子吧。这是一ơFTP的连接,呵呵Q是cuteftp默认的cuteftp的FTP站点QIP地址是:216.3.226.21。我的IP地址假设?192.168.1.1。下面的数据是TCO/IPq接q程中的数据传输。我们可以分析TCP/IP协议数据格式以及TCP/IPq接的三ơ握手(ThreeWay-HandshakeQ情c下面的q些十六q制数据只是TCP/IP协议的数据,不是完整的网l通讯数据。
W一ơ,我向FTP站点发送连接请求(我把TCP数据的可选部分去掉了Q
192.168.1.1->216.3.226.21
IP头部Q?45 00 00 30 52 52 40 00 80 06 2c 23 c0 a8 01 01 d8 03 e2 15
TCP头部Q?d 28 00 15 50 5f a9 06 00 00 00 00 70 02 40 00 c0 29 00 00
来看看IP头部的数据是些什么。
W一字节Q?#8220;45”Q其?#8220;4”是IP协议的版本(VersionQ,说明是IP4?#8220;5”是IHL位,表示IP头部的长度,是一?bit字段Q最大就?111了,gؓ12QIP头部的最大长度就?0字节。而这里ؓ“5”Q说明是20字节Q这是标准的IP头部长度Q头部报文中没有发送可选部分数据。
接下来的一个字?#8220;00”是服务类型(Type of ServiceQ。这?bit字段?bit的优先权子字D(现在已经被忽略)Q? bit的TOS子字D以? bit的未用字D(现在?Q构?4 bit的TOS子字D包含:最g时、最大吞吐量、最高可靠性以及最费用构成,q四?bit位最多只能有一个ؓ1Q本例中都ؓ0Q表C是一般服务。
接着的两个字?#8220;00 30”是IP数据报文总长Q包含头部以及数据,q里表示48字节。这48字节?0字节的IP头部以及28字节的TCP头构成(本来截取的TCP头应该是28字节的,其中8字节为可选部分,被我省去了)。因此目前最大的IP数据包长度是65535字节。
再是两个字节的标志位QIdentificationQ:“5252”Q{换ؓ十进制就?1074。这个是让目的主机来判断新来的分D属于哪个分l。
下一个字?#8220;40”Q{换ؓ二进制就?#8220;0100 0000”Q其中第一位是IP协议目前没有用上的,?。接着的是两个标志DF和MF。DF?表示不要分段QMF?表示q有q一步的分段Q本例ؓ0Q。然后的“0 0000”是分D便U(Fragment OffsetQ。
“80”q个字节是TTLQTime To LiveQ了Q表CZ个IP数据的生命周期Q用Ping昄的结果,能得到TTL的|很多文章p通过TTL位来判别Lcd。因Z般主机都有默认的TTL|不同pȝ的默认g一栗比如WINDOWS?28。不q,一般Ping得到的都不是默认|q是因ؓ每次IP数据包经q一个\由器的时候TTL减一Q当减到0Ӟq个数据包就消亡了。这也时Tracert的原理。本例中?#8220;80”Q{换ؓ十进制就?28了,我用的WIN2000。
l箋下来的是“06”Q这个字节表CZ输层的协议类型(ProtocolQ。在RFC790中有定义Q?表示传输层是TCP协议。
“2c 23”q个16bit是头校验和(Header ChecksumQ。
接下?#8220;c0 a8 01 01”Q这个就是源地址QSource AddressQ了Q也是我的IP地址?
转换为十q制的IP地址是Q?92.168.1.1Q同Pl箋下来?2?#8220;d8 03 e2 15”是目标地址Q?16.3.226.21
好了Q真累啊Q终于看完基本的20字节的IP数据报头了。l看TCP的头部吧Q这个是作ؓIP数据包的数据部分传输的。
TCP头部Q?d 28 00 15 50 5f a9 06 00 00 00 00 70 02 40 00 c0 29 00 00
一来就是一个两字节D?#8220;0d 28”Q表C本地端口号Q{换ؓ十进制就?368。第二个两字节段“00 15”表示目标端口Q因为我是连接FTP站点Q所以,q个是21啦,十六q制当然是“00 15”。
接下来的四个字节“50 5f a9 06”是顺序号QSequence NumberQ,写ؓSEQQSEQ=1348446470下面的四个字?#8220;00 00 00 00”是确认号QAcknowledgment NumberQ,写ؓACKNUM。
l箋两个字节Q?#8220;70 02”Q{换ؓ二进制吧Q?#8220;0111 0000 0000 0010”。这两个字节,d16bitQ有好多东西呢。第一?bit“0111”Q是TCP头长Q十q制?Q表C?8个字节(刚才说了Q我省略?字节的option数据Q所以你只看见了20字节Q。接着?bit现在TCP协议没有用上Q都?。最后的6bit“00 0010”是六个重要的标志。这是两个计机数据交流的信息标志。接收和发送断Ҏq些标志来确定信息流的种cR下面是一些介l:
URGQ(Urgent Pointer field significantQ紧急指针。用到的时候gؓ1Q用来处理避免TCP数据中断
ACKQ(Acknowledgment fieldsignificantQ置1时表C确认号QAcknowledgmentNumberQؓ合法Qؓ0的时候表C数据段不包含确认信息,认可忽略。
PSHQ(Push FunctionQ,PUSH标志的数据,|?时请求的数据D在接收方得到后可直接送到应用E序Q而不必等到缓冲区满时才传送。
RSTQ(Reset the connectionQ用于复位因某种原因引v出现的错误连接,也用来拒l非法数据和h。如果接收到RST位时候,通常发生了某些错误。
SYNQ(Synchronize sequence numbersQ用来徏立连接,在连接请求中QSYN=1QACK=0Q连接响应时QSYN=1QACK=1。即QSYN和ACK来区分Connection Request和Connection Accepted。
FINQ(No more data from senderQ用来释放连接,表明发送方已经没有数据发送了。
q?个标志位Q你们自己对号入座吧。本例中SYN=1QACK=0Q当然就是表C接请求了。我们可以注意下面两个过E的q两位的变换。
后面?#8220;40 00 c0 29 00 00”不讲了,呵呵Q偷懒了。后面两ơ通讯的数据,自己分开看吧。我们看看连接的q程Q一些重要地方的变化。
W二ơ,FTP站点q回一个可以连接的信号。
216.3.226.21->192.168.1.1
IP头部Q?45 00 00 2c c6 be 40 00 6a 06 cd ba d8 03 e2 15 c0 a8 01 01
TCP头部Q?0 15 0d 28 4b 4f 45 c1 50 5f a9 07 60 12 20 58 64 07 00 00
W三ơ,我确认连接。TCPq接建立h。
192.168.1.1->216.3.226.21
IP头部Q?45 00 00 28 52 53 40 00 80 06 2c 2a c0 a8 01 01 d8 03 e2 15
TCP头部Q?d 28 00 15 50 5f a9 07 4b 4f 45 c2 50 10 40 b0 5b 1c 00 00
好,我们看看整个Threeway_handshakeq程。
W一步,我发接请求,TCP数据为:SEQ=50 5f a9 06QACKNUM=00 00 00 00QSYN=1QACK=0。
W二步,Ҏ认可以q接QTCP数据为:SEQ=4b 4f 45 c1QACKNUM=50 5f a9 07QSYN=1QACK=1。
W三步,我确认徏立连接。SEQ=50 5f a9 07Q?ACKNUM=4b 4f45c2QSYN=0QACK=1。
可以看出什么变化么Q正式徏立连接了呢,q些东西是什么|
我接收从216.3.226.21->192.168.1.1的下一个数据包中:
SEQ=4b 4f 45 c2QACKNUM=50 5f a9 07,SYN=0,ACK=1q些都是很基的东西,对于~写snifferq样的东西是必须非常熟悉的。这里只讲解了TCP/IP协议的一点点东西Q主要是头部数据的格?/p>
以下用一个自创的对话框类(MyMessageDlg)向视囄(MessageTestView)
发送自定义消息ZQ说明这两种不同Ҏ的自定义消息?/span>
消息传递的Ҏ一Q用ON_MESSAGE
使用ON_MESSAGE响应消息Q必配合定义消?define WM_MY_MESSAGE (WM_USER+100)
对于发送消息?/span>-MyMessageDlgQ?br>在其MyMessageDlg.h中,定义#define WM_MY_MESSAGE (WM_USER+100)
在其MyMessageDlg.cpp中要先添加:Qi nclude "MainFrm.h"
因ؓ使用了CMainFrame*定义对象?br>q且要有试消息的函敎ͼ
void MyMessageDlg::OnButtonMsg()
{
// TODO: Add your control notification handler code here
CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
CView * active = pMF->GetActiveView();//才能获取当前视类指针
if(active != NULL) //获取了当前视cL针才能发送消?br> active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消?br>}
对于消息的接受?/span>-MessageTestViewQ?br>在其MessageTestView.h中,也要定义#define WM_MY_MESSAGE (WM_USER+100)
q定义消息映函?OnMyMessage()
protected:
//{{AFX_MSG(CMessageTestView)
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在其MessageTestView.cpp中,
先要声明响应消息Q?br>BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
//}}AFX_MSG_MAP
再添加消息响应的函数实现Q?br>LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
MessageBox("OnMyMessage!");
return 0;
}
消息传递的Ҏ二:使用ON_REGISTERED_MESSAGE
使用ON_REGISTERED_MESSAGE注册消息Q必配?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
对于消息的发送?/span>-MyMessageDlgQ?br>在其MyMessageDlg.h中,只要
定义static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
可以了?br>在其MyMessageDlg.cpp中要先添加:Qi nclude "MainFrm.h"
因ؓ使用了CMainFrame*定义对象?br>q且要有试消息的函敎ͼ
void MyMessageDlg::OnButtonMsg()
{
// TODO: Add your control notification handler code here
CMainFrame* pMF=(CMainFrame*)AfxGetApp()->m_pMainWnd; //先通过获取当前框架指针
CView * active = pMF->GetActiveView();//才能获取当前视类指针
if(active != NULL) //获取了当前视cL针才能发送消?br> active->PostMessage(WM_MY_MESSAGE,0,0); //使用PostMessage发送消?br>}
对于消息的接收?/span>-MessageTestViewQ?br>在其MessageTestView.h中不要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); ------------------------------------------------------------------- 其他注意事项Q?/p>
发送消息的-MyMessageDlg.cpp前也要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); 接受消息?MessageTestView.cpp前也要定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); RegisterWindowMessage("Message")?"的内Ҏ什么不重要Q写什么都可以Q但?br>发送者与接受者必L一L内容Q例如:"Message"
应该把这个定义放到MessageTestView.cpp中,要不会出? redefinition
在其MessageTestView.h中只要定义消息映函?br>protected:
//{{AFX_MSG(CMessageTestView)
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在其MessageTestView.cpp?先定?br>static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message");
接着注册消息Q?br>BEGIN_MESSAGE_MAP(CMessageTestView, CEditView)
//{{AFX_MSG_MAP(CMessageTestView)
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)
//}}AFX_MSG_MAP
最后添加消息响应的函数实现Q?br>LRESULT CMessageTestView::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
MessageBox("OnMyMessage!");
return 0;
}
----------------------------------------------------------------
比较两种ҎQ只是略有不同。但也要心谨慎Q以免出现接收不到消息的情况?/p>
]]>
#define WM_MY_MESSAGE (WM_USER+100) |
LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam) { // TODO: 处理用户自定义消? ... return 0; } |
class CMainFrame:public CMDIFrameWnd { ... // 一般消息映函? protected: // {{AFX_MSG(CMainFrame) afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); afx_msg void OnTimer(UINT nIDEvent); afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //}}AFX_MSG DECLARE_MESSAGE_MAP() } |
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd) //{{AFX_MSG_MAP(CMainFrame) ON_WM_CREATE() ON_WM_TIMER() ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage) //}}AFX_MSG_MAP END_MESSAGE_MAP() |
static UINT WM_MY_MESSAGE=RegisterWindowMessage("User"); |
DWORD result; SendMessageTimeout(wnd->m_hWnd, // 目标H口 WM_MY_MESSAGE, // 消息 0, // WPARAM 0, // LPARAM SMTO_ABORTIFHUNG | SMTO_NORMAL, TIMEOUT_INTERVAL, &result); |
ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //定义消息映射 视类定义消息处理函数Q?br> // 消息处理函数 LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam) { // TODO: 处理用户自定义消? ... return 0; } //发送消息的试函数 void CMainFrame::OnTest() { CView * active = GetActiveView();//获取当前视类指针 if(active != NULL) active->PostMessage(WM_MY_MESSAGE,0,0); } |
//发送消息的试函数 void CMainFrame::OnTest() { CMDIFrameWnd *pFrame; CMDIChildWnd *pChild; CView *pView; //获取ȝ口指?br>pFrame =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd; // 获取子窗口指?br>pChild = (CMDIChildWnd *) pFrame->GetActiveFrame(); //获取视类指针 pView = pChild->GetActiveView(); if(pView != NULL) pView->PostMessage(WM_MY_MESSAGE,0,0);//发送消?br>} |
//发送消息的试函数 void CMessageView::OnTest() { CFrameWnd * active = GetActiveFrame();//获取当前ȝ口框架指?br>if(active != this) active->PostMessage(WM_MY_MESSAGE,0,0); return 0; } |
//通过对话框按钮发送消息的函数 void TestDialog::OnDialogTest() { CMDIFrameWnd *pFrame; CMDIChildWnd *pChild; CView *pView; //获取ȝ口指?br>pFrame =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd; // 获取子窗口指?br>pChild = (CMDIChildWnd *) pFrame->GetActiveFrame(); //获取视类指针 pView = pChild->GetActiveView(); if(active != NULL) active->PostMessage(WM_MY_MESSAGE,0,0);//发送消?br>} |
static UINT WM_MY_MESSAGE=RegisterWindowMessage("Message"); |
protected: //{{AFX_MSG(CMessageView) //}}AFX_MSG afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam); //此行为添加代?br>DECLARE_MESSAGE_MAP() 在视cL件MessageView.cpp中的消息映射中添加自定义消息映射 BEGIN_MESSAGE_MAP(CMessageView, CView) //{{AFX_MSG_MAP(CMessageView) //}}AFX_MSG_MAP // Standard printing commands ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //此行d代码定义唯一消息 END_MESSAGE_MAP() |
LRESULT CMessageView::OnMyMessage(WPARAM wParam, LPARAM lParam) { CRect rect; GetClientRect(&rect); InvalidateRect(&rect); test=!test; return 0; } |
void CMessageView::OnDraw(CDC* pDC) { CMessageDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // 以下E序昄消息响应效果 if(test) pDC->TextOut(0,0,"消息响应!"); } |
#include "TestDialog.h"; OnTest()函数中添加代?br>void CMainFrame::OnTest() { TestDialog dialog; dialog.DoModal(); } |
如果不扯得太q的话(比如说操作系l中虚拟内存和物理内存如何运做如何管理之cȝ知识{)Q我感觉q篇文章应该是比较全面地谈了一下malloc()和free().q篇文章由浅入深Q不见得有多深)分三个部分介l主要内宏V?/p>
废话了那么多Q下面立刻进入主?===============》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》?/p>
一、malloc()和free()的基本概念以及基本用法:
1、函数原型及说明Q?/p>
void *malloc(long NumBytes)Q该函数分配了NumBytes个字节,q返回了指向q块内存的指针。如果分配失败,则返回一个空指针QNULLQ?/p>
关于分配p|的原因,应该有多U,比如说空间不_是一U?/p>
void free(void *FirstByte)Q?该函数是之前用malloc分配的空间还l程序或者是操作pȝQ也是释放了这块内存,让它重新得到自由?/p>
2、函数的用法Q?/p>
其实q两个函数用h倒不是很难,也就是malloc()之后觉得用够了就甩了它把它给free()了,举个单例子:
是q样Q当Ӟ具体情况要具体分析以及具体解冟뀂比如说Q你定义了一个指针,在一个函数里甌了一块内存然后通过函数q回传递给q个指针Q那么也讔R放这块内存这工作就应该留给其他函数了?/p>
3、关于函C用需要注意的一些地方:
A、申请了内存I间后,必须查是否分配成功?/p>
B、当不需要再使用甌的内存时Q记得释放;释放后应该把指向q块内存的指针指向NULLQ防止程序后面不心使用了它?/p>
C、这两个函数应该是配寏V如果申请后不释攑ְ是内存泄Ԍ如果无故释放那就是什么也没有做。释攑֏能一ơ,如果释放两次及两ơ以上会
出现错误Q释攄指针例外Q释攄指针其实也等于啥也没做,所以释攄指针释放多少ơ都没有问题Q?/p>
D、虽然malloc()函数的类型是(void *),Mcd的指针都可以转换?void *),但是最好还是在前面q行强制cd转换Q因样可以躲q一
些编译器的检查?/p>
好了Q最基础的东西大概这么说Q现在进入第二部分:
二、malloc()到底从哪里得来了内存I间Q?/p>
1、malloc()到底从哪里得C内存I间Q答案是从堆里面获得I间。也是说函数返回的指针是指向堆里面的一块内存。操作系l中有一个记录空 闲内存地址的链表。当操作pȝ收到E序的申hQ就会遍历该链表Q然后就LW一个空间大于所甌I间的堆l点Q然后就该l点从空闲结炚w表中删除Qƈ 该l点的空间分配给E序。就是这P
说到q里Q不得不另外插入一个小话题Q相信大家也知道是什么话题了。什么是堆?说到堆,又忍不住说到了栈Q什么是栈?下面另外开个小部分专门而又单地说一下这个题外话Q?/p>
2、什么是堆:堆是大家共有的空_分全局堆和局部堆。全局堆就是所有没有分配的I间Q局部堆是用户分配的空间。堆在操作系l对q程 初始化的时候分配,q行q程中也可以向系l要额外的堆Q但是记得用完了要还l操作系l,要不然就是内存泄漏?/p>
什么是栈:栈是U程独有的,保存其运行状态和局部自动变量的。栈在线E开始的时候初始化Q每个线E的栈互相独立。每个函数都有自q栈,栈被用来在函C 间传递参数。操作系l在切换U程的时候会自动的切换栈Q就是切换SS/ESP寄存器。栈I间不需要在高语言里面昑ּ的分配和释放?
以上的概忉|q是标准的描qͼ不过有个别语句被我删除,不知道因栯变得不标准了^_^.
通过上面Ҏ늚描述Q可以知道:
栈是q译器自动分配释放Q存攑և数的参数倹{局部变量的值等。操作方式类g数据l构中的栈?/p>
堆一般由E序员分配释放,若不释放Q程序结束时可能由OS回收。注意这里说是可能,q一定。所以我惛_一ơ,记得要释放!
注意它与数据l构中的堆是两回事,分配方式倒是cM于链表?br>所以,举个例子Q如果你在函C面定义了一个指针变量,然后在这个函数里甌了一块内存让指针指向它。实际上Q这个指针的地址是在栈上Q但是它所指向的内容却是在堆上面的Q这一点要注意Q所以,再想惻I在一个函数里甌了空间后Q比如说下面q个函数Q?
p个例子,千万不要认ؓ函数q回Q函数所在的栈被销毁指针也跟着销毁,甌的内存也׃栯着销毁了Q这l对是错误的Q因为申L内存在堆上,而函数所在的栈被销毁跟堆完全没有啥关系。所以,q是那句话:记得释放Q?/p>
3、free()到底释放了什?/p>
q个问题比较单,其实我是惛_W二大部分的题目相呼应而已Q哈哈!free()释放的是指针指向的内存!注意Q释攄是内存,不是指针Q这炚w帔R帔R 要!指针是一个变量,只有E序l束时才被销毁。释放了内存I间后,原来指向q块I间的指针还是存在!只不q现在指针指向的内容的垃圾,是未定义的,所以说 是垃圾。因此,前面我已l说q了Q释攑ֆ存后把指针指向NULLQ防止指针在后面不小心又被解引用了。非帔R要啊q一点!
好了Q这?#8220;题外?#8221;l于说完了。就q么单说一ơ,知道个大概就可以了!下面p入第三个部分Q?/p>
三、malloc()以及free()的机Ӟ
q个部分我今天才有了新的认识Q而且是{折性的认识Q所以,q部分可能会有更多一些认识上的错误!不对的地方请大家帮忙指出Q?/p>
事实上,仔细看一下free()的函数原型,也许也会发现g很神奇,free()函数非常单,只有一个参敎ͼ只要把指向申L间的指针传?/p>
lfree()中的参数可以完成释攑ַ作!q里要追t到malloc()的申请问题了。申L时候实际上占用的内存要比申L大。因出的I间是用来记录对q块内存的管理信息。先看一下在《UNIX环境高~程》中W七章的一D话Q?/p>
大多数实现所分配的存储空间比所要求的要E大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等{。这意味着如果写过一个已 分配区的Q则会改写后一块的理信息。这U类型的错误是灾难性的Q但是因U错误不会很快就暴露出来Q所以也很隑֏现。将指向分配块的指针向后U? 动也可能会改写本块的理信息?/p>
以上q段话已l给了我们一些信息了。malloc()甌的空间实际我觉得是分了两个不同性质的空间。一个就是用来记录管理信息的I间Q另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中,用结构体来记录同一个对象的不同信息?/p>
天经C的事Q下面看看这个结构体的原型:
对于size,q个是实际空间大。这里其实我有个疑问Qis_available是否是一个标讎ͼ因ؓ我看了free()的源代码之后对这个变量感觉有点纳P源代码在下面分析Q。这里还请大家指出!
所以,free()是Ҏq个l构体的信息来释放malloc()甌的空_而结构体的两个成员的大小我想应该是操作系l的事了。但是这里有一个问 题,malloc()甌I间后返回一个指针应该是指向W二U空_也就是可用空_不然Q如果指向管理信息空间的话,写入的内容和l构体的cd有可能不 一_或者会把管理信息屏蔽掉Q那没法释攑ֆ存空间了Q所以会发生错误Q(感觉自己q里说的是废话)
好了Q下面看看free()的源代码Q我自己分析了一下,觉得比vmalloc()的源代码倒是Ҏ单很多。只是有个疑问,下面指出Q?/p>
看一下函数第二句Q这句非帔R要和关键。其实这句就是把指向可用I间的指针倒回去,让它指向理信息的那块空_因ؓq里是在g减去了一个结构体的大 !后面那一句free->is_available = 1;我有点纳P我的x是:q里is_available应该只是一个标记而已Q因Zq个变量的名UC来看Qis_available 译q来是“是可以用”。不要说我土Q我觉得变量名字可以反映一个变量的作用Q特别是严}的代码。这是源代码Q所以我觉得l对是严谨的Q!q个变量的? ?Q表明是可以用的I间Q只是这里我想了惻I如果把它改ؓ0或者是其他g知道会发生什么事Q!但是有一Ҏ可以肯定Q就是释攄对不会那么顺利进行! 因ؓq是一个标讎ͼ
当然Q这里可能还是有Z有疑问,Z么这样就可以释放呢?Q我刚才也有q个疑问。后来我惛_Q释放是操作pȝ的事Q那么就free()q个源代码来看, 什么也没有释放Q对吧?但是它确实是定了管理信息的那块内存的内宏V所以,free()只是记录了一些信息,然后告诉操作pȝ那块内存可以去释放,具体 怎么告诉操作pȝ的我不清楚,但我觉得q个已经出了我q篇文章的讨围了?/p>
那么Q我之前有个错误的认识,是认ؓ指向那块内存的指针不移到那块内存中的哪个位|都可以释放那块内存Q但是,q是大错牚wQ释放是不可以释放一部分 的!首先q点应该要明白。而且Q从free()的源代码看,ptr只能指向可用I间的首地址Q不Ӟ减去l构体大之后一定不是指向管理信息空间的首地 址。所以,要确保指针指向可用空间的首地址Q不信吗Q自己可以写一个程序然后移动指向可用空间的指针Q看E序会有会崩Q?/p>
最后可能想到malloc()的源代码看看malloc()到底是怎么分配I间的,q里面涉及到很多其他斚w的知识!有兴的朋友可以自己M载源
代码ȝ看?/p>
四、关于其他:
unsigned long inet_addr (const char *cp);
inet_addr一个点分十q制IP地址字符串{换成32位数字表C的IP地址Q网l字节顺序)?/p>
char* inet_ntoa (struct in_addr in);
inet_ntoa一?2位数字表C的IP地址转换成点分十q制IP地址字符丌Ӏ?/p>
q两个函C为反函数
字节序转换
htons()--"Host to Network Short"
htonl()--"Host to Network Long"
ntohs()--"Network to Host Short"
ntohl()--"Network to Host Long"
*注意:在你的数据放到网l上的时候,信它是|络字节序
|络字节序(大端字节)和x86机器字节序(端字节)
eg:0X3132 在x86上显C?1 在网l传输中?2