使用TCP SOCKET 成功连接以后,使用recv函数接收数据,内存的情况是怎样的呢?不做测试真的不知道内幕原来如此:
一个已经取得连接的TCP socket sockConn 两次接收数据的代码如下:
char buf1[16];
recv(sockConn,buf1,16,0);
MessageBox(buf1);
char buf2[16];
recv(sockConn,buf2,16,0);
MessageBox(buf2);
与sockConn连接的另外一个TCP socket sockClient 两次发送数据的代码如下:
send(sockClient,"sendmessage1",strlen("sendmessage1")+1,0); //包含字符串结束符,共发送13字节。
send(sockClient,"sendmessage2",strlen("sendmessage2"),0); //不包含字符串结束符,共发送12字节。
sockConn的第一个messageBox(buf1);结果是sendmessage1,而第二个MessageBox(buf2);结果是sendmessage2烫烫sendmessage1。这时我就估计到内存的情况应该如下图所示:
也 就是说buf2的内存空间刚好排在前一个接收数据容器buf1的前面,我估计这就是所谓的TCP数据流的意义吧,接收到的数据会连在一起,流式的。当使用 MessageBox(buf2)输出buf2的时候,就一直输出,直到遇到后面buf1第13个字节的结束符/0为止,所以就看到上面的输出结果了。
看回sockConn第二次接收数据的语句,recv(sockConn,buf2,16,0);参数16是控制接收数据的字节数,其实这个参数并不一定就要是buf的大小,它可以取任何大于0的整数值,如果我把sockClient第二次发送的语句改为:
send(sockClient,"sendmessage2ABCDEF",strlen("sendmessage2ABCDEF"),0); //不包含字符串结束符,共发送18字节。
哪 么MessageBox(buf2);的结果就是sendmessage2ABCDsendmessage1,因为 recv(sockConn,buf2,16,0);的参数16规定了最多只接收16个字节的数据,所以把数据“EF”丢弃掉。如果把 recv(sockConn,buf2,16,0);改为recv(sockConn,buf2,18,0);哪么MessageBox(buf2);的 结果就是sendmessage2ABCDEFndmessage1,因为buf2只有16个字节的大小,接收到的第17、18个字节“EF”就跟着 buf2的末端继续写入内存,于是就把buf1的“se”改为“EF”了。如果改为recv(sockConn,buf2,20,0);哪么 MessageBox(buf2);的结果还是sendmessage2ABCDEFndmessage1,buf1的第三第四个字节空间里面的数据 “nd”不会被改写,因为接收到的数据还用不到这里的空间。
简单的说,recv函数的第三个参数就像是一个闸门,接收到的数据写入内存时禁 止越过这个闸门,如果闸门前的内存不够写入全部接收到的数据,那就把后面无法写入的哪部分数据丢弃。如果闸门前的内存让全部接收到的数据写入后还有多余 的,那多余的内存会保留原本的值,并不会被改写。
甚至还可以改为 recv(sockConn,buf2,40,0);buf1加上buf2总共才32个字节,而我把recv的第三个参数改为40,如果 sockClient发送了50个字节,前40个字节的内容能成功写入内存。要注意的是,在buf1后面新开辟出来的8个字节内存空间,是在 buf2+buf1不够内存写入数据的时候才根据需要开辟的,例如如果sockClient只发送了30个字节,那么buf1后面是不会开辟任何内存空间 的。而如果sockClient只发送了37个字节,那么buf1后面只开辟5个字节的内存空间而不是开辟8个字节的内存空间的。
来源:http://light6891.blog.163.com/blog/static/9696290920096290157187/