如何清空Socket缓冲区

时间:2023-02-01 09:00:56
有什么办法能一次性吧缓冲区的内容全部Recv下来呢?
用While循环会有这样的问题
比如
while(true)
{
int ret = recv(socket, buf, 500,0);
if(ret != 500)
{
break;
}
}
那么当我缓冲区内的消息正好是500的倍数的时候,第一次ret=500 不退出循环 下一次recv因为缓冲区内没有消息,就会堵塞!

有什么好办法能不阻塞 把缓冲区的消息都接下来么?

33 个解决方案

#1


!=改成<=

#2


错了 是< 
刚睡醒真晕

#3


如果你是用的阻塞模式那么你一次recv的就是全的数据包啊,如果是异步模式那你得自己处理,比如自己定义包头,在包头里存上数据的长度,收数据的时候统计一下

#4


一次Recv是全部数据包?
不是的吧 是根据我提供的长度来接受的
int ret = recv(socket, buf, 500,0);
就是接收500个 多的会继续留在缓存区的

至于改成< 那是完全一样的  因为不可能大于的

#5


引用 4 楼 ohyeah_dragon 的回复:
一次Recv是全部数据包?
不是的吧 是根据我提供的长度来接受的
int ret = recv(socket, buf, 500,0);
就是接收500个 多的会继续留在缓存区的

至于改成< 那是完全一样的 因为不可能大于的

啊这个样啊,那这首先是你设计有问题,不应该出现巨大的数据包的,缓冲区的长度一般是1K,或者4K,然后对于这样的处理那就是判断一下recv到的字节数呗,所以说得在内数据里面设计一个包头,这样当缓冲区满了的时候才能知道一个完整的包是不是都收到了,并且也能知道包的边界

#6


引用 4 楼 ohyeah_dragon 的回复:
一次Recv是全部数据包?
不是的吧 是根据我提供的长度来接受的
int ret = recv(socket, buf, 500,0);
就是接收500个 多的会继续留在缓存区的

至于改成< 那是完全一样的 因为不可能大于的



改成小于  最后一次收完不就break了?

#7


int length = 500;
int recvlen = 0;
int len = 0;
while(length-recvlen>0){
    len = read(sock, buf, length);
     recvlen+=len;
}

#8


while(RecLen > 0)
即可,为啥要用while(1)???

#9


我想大家搞错了我的意思 我现在要实现的是清空缓冲区 而不是正常收发报文
是这样的 我的收发模式是根据先发送的包长度来接收剩下的报文
但是如果包长度和接收到的长度不符合的话
为了不影响接下来的报文的正确收发 ,我需要清空缓冲区
但是为了打出日志来(毕竟有可能清掉之后的正确报文),所以最好是能把清掉的内容输入到日志
因此最后要实现的就是接收缓冲区内所有数据

#10


引用 7 楼 ak_kay 的回复:
C/C++ code
int length = 500;
int recvlen = 0;
int len = 0;
while(length-recvlen>0){
    len = read(sock, buf, length);
     recvlen+=len;
}


你这是知道了要接受500的长度 所以这么做,,但是实际上我并不知道缓冲区里有多少消息的

#11


本身你用的TCP,它是流式协议,也就是说就不应该有块状缓冲区的概念,你应该当做一个数据流去处理。像你说的出现长度不符的情况也不应该去清空缓冲区,而是继续接收,自然就可以收到你需要的长度了。

#12


不是这样的
比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度

那么这时候我接收到的长度就和发送的长度不符  如果不清空缓冲区
那么当下一个报文进来的时候,就会把下一个报文的2个长度算成是前一个报文
导致下一个报文错位
连带后面全部的报文都错位!
这是非常严重的

#13


你RECV的时候,数据就都在网卡 缓存里了,只要你空间足够就能一次收完。。。。
你想清空缓冲区的话,就在RECV并且判断返回值,返回值是退出条件。。

#14


但是Recv要提供你要接受的长度的
recv(socket, buf, 500,0);
第三个参数是你要接受的长度
如果小了 就会一次接收不完
但是要大的话是没有上限的把

#15


引用 12 楼 ohyeah_dragon 的回复:
不是这样的

比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度 //每个包都是有长度的~~
到的长度就和发送的长度不符 如果不清空缓冲区  //长度不符合,怎么保证稳定性~~
那么当下一个报文进来的时候,就会把下一个报文的2个长度算成是前一个报文 //先判断包头不就可以了~~
导致下一个报文错位
连带后面全部的报文都错位!
这是非常严重的


你只需要读到你想要的东西就可以了

#16


我现在考虑的就是故障处理
因为我做的通讯是会有外部链接进来的 我不能保证别人的报文一定就正确
我总不能他出错我就当掉吧

比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度 //每个包都是有长度的~~//现在就是考虑长度出错的情况
到的长度就和发送的长度不符 如果不清空缓冲区 //长度不符合,怎么保证稳定性~~//那边的程序不是我写的,不符合也是有可能的
那么当下一个报文进来的时候,就会把下一个报文的2个长度算成是前一个报文 //先判断包头不就可以了~~//都错位了,包头当然也是错的  无从判断

#17


引用 16 楼 ohyeah_dragon 的回复:
我现在考虑的就是故障处理
因为我做的通讯是会有外部链接进来的 我不能保证别人的报文一定就正确
我总不能他出错我就当掉吧

比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度 //每个包都是有长度的~~//现在就是考虑长度出错的情况
到的长度就和发送的长度不符 如果不清空缓冲区 //长度不符合,怎么保证稳定性~~//那边的程序不是我写的,不符合也是有可能的
那么当下一个报……


你没明白流式协议该如何解析。

一般都是这样解析的

你应该有一个单独组合数据包的过程,有一个数据缓冲

首先读出包头的长度,然后就“期待”读够包头,然后解析包头得出数据长度,然后在“期待”读够数据.

至于具体实现可以考虑用个队列,队尾加数据进去,从队头开始解析.

#18


引用 17 楼 zhanshen2891 的回复:
你没明白流式协议该如何解析。

一般都是这样解析的

你应该有一个单独组合数据包的过程,有一个数据缓冲

首先读出包头的长度,然后就“期待”读够包头,然后解析包头得出数据长度,然后在“期待”读够数据.

至于具体实现可以考虑用个队列,队尾加数据进去,从队头开始解析.

我现在在做的就是异常处理啊,。。
然后就“期待”读够包头//读错了、不够了怎么处理
我要做的就是这个啊
不可能永远是对啊
我的程序也不能对方发一个错的报文他就当掉啊

#19


自己定议个协议头不就搞定了,每个包不都有规律了

#20


用非阻塞的IO,select轮询机制

#21


引用 19 楼 bcj00000 的回复:
自己定议个协议头不就搞定了,每个包不都有规律了

为什么都不理解我的意思呢?
我定了协议!
按照协议走完全没问题!
但是我现在是在做异常处理!
我要考虑出异常的情况!

#22


能不能别再纠结什么协议什么做法
我的问题是怎么清空Socket缓冲区的内容
请回答我这个问题好么 各位大大们

#23


清空的话可以用memset做。
但是考虑到你的情况,建议你在发送的时候,把将要发送的大小发送到接受方,这样就可以很好的操作了利用循环,以及统计接收的总字节数就可以了

#24


引用 18 楼 ohyeah_dragon 的回复:
引用 17 楼 zhanshen2891 的回复:
你没明白流式协议该如何解析。

一般都是这样解析的

你应该有一个单独组合数据包的过程,有一个数据缓冲

首先读出包头的长度,然后就“期待”读够包头,然后解析包头得出数据长度,然后在“期待”读够数据.

至于具体实现可以考虑用个队列,队尾加数据进去,从队头开始解析.

我现在在做的就是异常处理啊,。。
然后就“期待”读够包……


不会出现读错了和上一个包没读够而下一个包的数据就来了的情况,那是绝对不会出现的,因为你用的是TCP,它已经帮你处理过了

#25


不是底层读错
是应用层可能组包组错啊

可能我20长度的包 因为程序写错了 前面的包长度写成2了呢

#26


引用 25 楼 ohyeah_dragon 的回复:
不是底层读错
是应用层可能组包组错啊

可能我20长度的包 因为程序写错了 前面的包长度写成2了呢


校验包头,在你这种情况,前1个包可以解析出来,但是下一个包头就校验不过了,这时候直接踢掉客户端

#27


踢掉客户端是一个办法
但是感觉不太好
我还是希望能清空缓冲区
牺牲掉下一个报文 保证后续的报文不会出错 程序也不会当掉
能实现么

#28


引用 27 楼 ohyeah_dragon 的回复:
踢掉客户端是一个办法
但是感觉不太好
我还是希望能清空缓冲区
牺牲掉下一个报文 保证后续的报文不会出错 程序也不会当掉
能实现么


据我所知那是不行的,你可以移动指针,不停校验新的包头,直到找到正确的包头,再开始新的解析。同样,你要是想保证数据也正确的话那就对数据也加个校验和。

但是,这种方法真的很不好,到时候出BUG你就知道有多难受了

#29


建议断开连接。你怎么知道现在的socket缓冲区中的数据哪些是肮脏的,哪些是正义的?

#30


《TCP/IP详解卷一:协议》

#31


引用 8 楼 walkersfaint 的回复:
while(RecLen > 0)
即可,为啥要用while(1)???

不要使用
while (条件)
更不要使用
while (组合条件)
要使用
while (1) {
 if (条件1) break;
 //...
 if (条件2) continue;
 //...
 if (条件3) return;
 //...
}
因为前两种写法在语言表达意思的层面上有二义性,只有第三种才忠实反映了程序流的实际情况。
典型如:
下面两段的语义都是当文件未结束时读字符
whlie (!feof(f)) {
 a=fgetc(f);
 //...
 b=fgetc(f);//可能此时已经feof了!
 //...
}
而这样写就没有问题:
whlie (1) {
 a=fgetc(f);
 if (feof(f)) break;
 //...
 b=fgetc(f);
 if (feof(f)) break;
 //...
}
类似的例子还可以举很多。

#32


好 我知道了 那我采用断开连接的方式吧  谢谢大家

#33


我就是采用断开连接的方式啊。。但是不知道为什么原因程序还是运行一会儿就不触发OnReceive和Send了。。。伤不起。。。用按钮的方式也不能触发OnReveive.......

#1


!=改成<=

#2


错了 是< 
刚睡醒真晕

#3


如果你是用的阻塞模式那么你一次recv的就是全的数据包啊,如果是异步模式那你得自己处理,比如自己定义包头,在包头里存上数据的长度,收数据的时候统计一下

#4


一次Recv是全部数据包?
不是的吧 是根据我提供的长度来接受的
int ret = recv(socket, buf, 500,0);
就是接收500个 多的会继续留在缓存区的

至于改成< 那是完全一样的  因为不可能大于的

#5


引用 4 楼 ohyeah_dragon 的回复:
一次Recv是全部数据包?
不是的吧 是根据我提供的长度来接受的
int ret = recv(socket, buf, 500,0);
就是接收500个 多的会继续留在缓存区的

至于改成< 那是完全一样的 因为不可能大于的

啊这个样啊,那这首先是你设计有问题,不应该出现巨大的数据包的,缓冲区的长度一般是1K,或者4K,然后对于这样的处理那就是判断一下recv到的字节数呗,所以说得在内数据里面设计一个包头,这样当缓冲区满了的时候才能知道一个完整的包是不是都收到了,并且也能知道包的边界

#6


引用 4 楼 ohyeah_dragon 的回复:
一次Recv是全部数据包?
不是的吧 是根据我提供的长度来接受的
int ret = recv(socket, buf, 500,0);
就是接收500个 多的会继续留在缓存区的

至于改成< 那是完全一样的 因为不可能大于的



改成小于  最后一次收完不就break了?

#7


int length = 500;
int recvlen = 0;
int len = 0;
while(length-recvlen>0){
    len = read(sock, buf, length);
     recvlen+=len;
}

#8


while(RecLen > 0)
即可,为啥要用while(1)???

#9


我想大家搞错了我的意思 我现在要实现的是清空缓冲区 而不是正常收发报文
是这样的 我的收发模式是根据先发送的包长度来接收剩下的报文
但是如果包长度和接收到的长度不符合的话
为了不影响接下来的报文的正确收发 ,我需要清空缓冲区
但是为了打出日志来(毕竟有可能清掉之后的正确报文),所以最好是能把清掉的内容输入到日志
因此最后要实现的就是接收缓冲区内所有数据

#10


引用 7 楼 ak_kay 的回复:
C/C++ code
int length = 500;
int recvlen = 0;
int len = 0;
while(length-recvlen>0){
    len = read(sock, buf, length);
     recvlen+=len;
}


你这是知道了要接受500的长度 所以这么做,,但是实际上我并不知道缓冲区里有多少消息的

#11


本身你用的TCP,它是流式协议,也就是说就不应该有块状缓冲区的概念,你应该当做一个数据流去处理。像你说的出现长度不符的情况也不应该去清空缓冲区,而是继续接收,自然就可以收到你需要的长度了。

#12


不是这样的
比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度

那么这时候我接收到的长度就和发送的长度不符  如果不清空缓冲区
那么当下一个报文进来的时候,就会把下一个报文的2个长度算成是前一个报文
导致下一个报文错位
连带后面全部的报文都错位!
这是非常严重的

#13


你RECV的时候,数据就都在网卡 缓存里了,只要你空间足够就能一次收完。。。。
你想清空缓冲区的话,就在RECV并且判断返回值,返回值是退出条件。。

#14


但是Recv要提供你要接受的长度的
recv(socket, buf, 500,0);
第三个参数是你要接受的长度
如果小了 就会一次接收不完
但是要大的话是没有上限的把

#15


引用 12 楼 ohyeah_dragon 的回复:
不是这样的

比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度 //每个包都是有长度的~~
到的长度就和发送的长度不符 如果不清空缓冲区  //长度不符合,怎么保证稳定性~~
那么当下一个报文进来的时候,就会把下一个报文的2个长度算成是前一个报文 //先判断包头不就可以了~~
导致下一个报文错位
连带后面全部的报文都错位!
这是非常严重的


你只需要读到你想要的东西就可以了

#16


我现在考虑的就是故障处理
因为我做的通讯是会有外部链接进来的 我不能保证别人的报文一定就正确
我总不能他出错我就当掉吧

比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度 //每个包都是有长度的~~//现在就是考虑长度出错的情况
到的长度就和发送的长度不符 如果不清空缓冲区 //长度不符合,怎么保证稳定性~~//那边的程序不是我写的,不符合也是有可能的
那么当下一个报文进来的时候,就会把下一个报文的2个长度算成是前一个报文 //先判断包头不就可以了~~//都错位了,包头当然也是错的  无从判断

#17


引用 16 楼 ohyeah_dragon 的回复:
我现在考虑的就是故障处理
因为我做的通讯是会有外部链接进来的 我不能保证别人的报文一定就正确
我总不能他出错我就当掉吧

比如我发一个长度60的报文 但是因为鼓掌 实际上我的报文时58长度 //每个包都是有长度的~~//现在就是考虑长度出错的情况
到的长度就和发送的长度不符 如果不清空缓冲区 //长度不符合,怎么保证稳定性~~//那边的程序不是我写的,不符合也是有可能的
那么当下一个报……


你没明白流式协议该如何解析。

一般都是这样解析的

你应该有一个单独组合数据包的过程,有一个数据缓冲

首先读出包头的长度,然后就“期待”读够包头,然后解析包头得出数据长度,然后在“期待”读够数据.

至于具体实现可以考虑用个队列,队尾加数据进去,从队头开始解析.

#18


引用 17 楼 zhanshen2891 的回复:
你没明白流式协议该如何解析。

一般都是这样解析的

你应该有一个单独组合数据包的过程,有一个数据缓冲

首先读出包头的长度,然后就“期待”读够包头,然后解析包头得出数据长度,然后在“期待”读够数据.

至于具体实现可以考虑用个队列,队尾加数据进去,从队头开始解析.

我现在在做的就是异常处理啊,。。
然后就“期待”读够包头//读错了、不够了怎么处理
我要做的就是这个啊
不可能永远是对啊
我的程序也不能对方发一个错的报文他就当掉啊

#19


自己定议个协议头不就搞定了,每个包不都有规律了

#20


用非阻塞的IO,select轮询机制

#21


引用 19 楼 bcj00000 的回复:
自己定议个协议头不就搞定了,每个包不都有规律了

为什么都不理解我的意思呢?
我定了协议!
按照协议走完全没问题!
但是我现在是在做异常处理!
我要考虑出异常的情况!

#22


能不能别再纠结什么协议什么做法
我的问题是怎么清空Socket缓冲区的内容
请回答我这个问题好么 各位大大们

#23


清空的话可以用memset做。
但是考虑到你的情况,建议你在发送的时候,把将要发送的大小发送到接受方,这样就可以很好的操作了利用循环,以及统计接收的总字节数就可以了

#24


引用 18 楼 ohyeah_dragon 的回复:
引用 17 楼 zhanshen2891 的回复:
你没明白流式协议该如何解析。

一般都是这样解析的

你应该有一个单独组合数据包的过程,有一个数据缓冲

首先读出包头的长度,然后就“期待”读够包头,然后解析包头得出数据长度,然后在“期待”读够数据.

至于具体实现可以考虑用个队列,队尾加数据进去,从队头开始解析.

我现在在做的就是异常处理啊,。。
然后就“期待”读够包……


不会出现读错了和上一个包没读够而下一个包的数据就来了的情况,那是绝对不会出现的,因为你用的是TCP,它已经帮你处理过了

#25


不是底层读错
是应用层可能组包组错啊

可能我20长度的包 因为程序写错了 前面的包长度写成2了呢

#26


引用 25 楼 ohyeah_dragon 的回复:
不是底层读错
是应用层可能组包组错啊

可能我20长度的包 因为程序写错了 前面的包长度写成2了呢


校验包头,在你这种情况,前1个包可以解析出来,但是下一个包头就校验不过了,这时候直接踢掉客户端

#27


踢掉客户端是一个办法
但是感觉不太好
我还是希望能清空缓冲区
牺牲掉下一个报文 保证后续的报文不会出错 程序也不会当掉
能实现么

#28


引用 27 楼 ohyeah_dragon 的回复:
踢掉客户端是一个办法
但是感觉不太好
我还是希望能清空缓冲区
牺牲掉下一个报文 保证后续的报文不会出错 程序也不会当掉
能实现么


据我所知那是不行的,你可以移动指针,不停校验新的包头,直到找到正确的包头,再开始新的解析。同样,你要是想保证数据也正确的话那就对数据也加个校验和。

但是,这种方法真的很不好,到时候出BUG你就知道有多难受了

#29


建议断开连接。你怎么知道现在的socket缓冲区中的数据哪些是肮脏的,哪些是正义的?

#30


《TCP/IP详解卷一:协议》

#31


引用 8 楼 walkersfaint 的回复:
while(RecLen > 0)
即可,为啥要用while(1)???

不要使用
while (条件)
更不要使用
while (组合条件)
要使用
while (1) {
 if (条件1) break;
 //...
 if (条件2) continue;
 //...
 if (条件3) return;
 //...
}
因为前两种写法在语言表达意思的层面上有二义性,只有第三种才忠实反映了程序流的实际情况。
典型如:
下面两段的语义都是当文件未结束时读字符
whlie (!feof(f)) {
 a=fgetc(f);
 //...
 b=fgetc(f);//可能此时已经feof了!
 //...
}
而这样写就没有问题:
whlie (1) {
 a=fgetc(f);
 if (feof(f)) break;
 //...
 b=fgetc(f);
 if (feof(f)) break;
 //...
}
类似的例子还可以举很多。

#32


好 我知道了 那我采用断开连接的方式吧  谢谢大家

#33


我就是采用断开连接的方式啊。。但是不知道为什么原因程序还是运行一会儿就不触发OnReceive和Send了。。。伤不起。。。用按钮的方式也不能触发OnReveive.......