为啥我的socket接收大数据的时候接收不完全

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为啥我的socket接收大数据的时候接收不完全相关的知识,希望对你有一定的参考价值。

TCP协议通信,接收方接收数据的前后次序与发送方一致,但数据包不一定一致。打个比方,发送方按顺序发送了2个数据包,接收可能仅接收1次就能全部收到,也可能需要收2次才能收到,也可能收3次,每次收到的数据大小不一定和发送方发送的数据包大小一样,但最终收到的总数据是一致的。
从你的程序来看,客户端连续发送2包数据,服务器端有可能一次就全部接到,也可能分2次收到,也可能会收2次以上才能收到。如果在发送“########helloworld”和“######whatisit”之间增加一些延时语句,比如延时1秒,那么可以肯定服务器端只能收到1次,因为在发送第1包数据的时候,服务器端就接收到一次数据,而在发送第2包数据时,服务器已经不再有接收动作了。
就现在的客户端程序来说,如果要在服务器端收到所有数据,可以考虑在服务器端循环接收数据,拼装数据,直到收不到数据为止,然后输出所有接收到的数据。
while(1)

int rr;
sock_fd = accept( sock, NULL, NULL);
retval = 0;
while(1)

rr = recv( sock_fd, buf1, MAX_BUFLEN, 0 );
if(rr==0) break;
memcpy(buf+retval,buf1,rr);
retval+=rr;

printf("buf= %s\n ##retval=%d\n",buf,retval);
write(sock_fd,"get the call\n",sizeof("get the call\n")-1);

可以试试看。仅供参考。

查到个函数ioctlsocket
while(1)
int rr;
sock_fd = accept( sock, NULL, NULL);
retval = 0;
int iMode = 1; //0:阻塞
ioctlsocket(sock_fd,FIONBIO, (u_long FAR*) &iMode);//非阻塞设置
while(1) .......
........
参考技术A 一次读取不完整 多次读 然后把读到的连接起来 如果是udp应该是丢包了 让发送方重发……

C# Sockets,接收大文件

【中文标题】C# Sockets,接收大文件【英文标题】:C# Sockets, receive big files 【发布时间】:2012-02-10 07:06:25 【问题描述】:

我现在正在使用异步套接字。我有一个回调函数'onDataReceived',每当我收到任何数据时都会触发它。

首先我一次只得到一个字符,所以我将 socketPacket 数据缓冲区更改为一个大数组。现在,每当我收到数据时,我都会一次获得所有数据,但是当我尝试发送更大的文件时,一旦超过数组大小,它就无法工作。

我的问题是这样的。我有一个多线程套接字服务器。我如何确定何时收到所有数据?例如我需要发送一个图像,我将图像编码为base64并构造一个命令“BASE64IMAGE”,然后服务器读取字符串直到它到达END_OF_DATA?有更好的方法吗?谢谢!

【问题讨论】:

您可以使用 HTTP 协议发送文件,这样您就可以使用 http 标头来表示有关正在发送的数据的详细信息 ..基于 http 的套接字类也可作为库使用 【参考方案1】:

我的问题是这样的。我有一个多线程套接字服务器。如何确定何时收到所有数据?

发送“消息”有三个标准选项(无论是图像还是其他什么 - 可能很大的一整块数据):

每个连接一条消息:您可以通过另一端关闭连接来检测消息的结束 某种“结束消息”标记:当您读取数据时,您会检查一个指示消息结束的特殊标记。如果标记可以自然发生,则需要将其转义 - 并在阅读时取消转义 在发送实际数据之前指示消息大小的标头 - 只需读取那么多字节

就我个人而言,我喜欢最后一个选项 - 它可以读取数据并确保您获得的所有内容都比前两个选项简单得多。您可以在开始之前分配适量的内存来接收数据等。但是,当您在开始之前不知道消息大小时,它就不能很好地应对。您可以通过为单个消息设置多个“块”来修改方案,其中您发送块大小然后发送数据,块大小为 0 表示数据结束。

请注意,如果您仅通过套接字传输数据,并且您不需要需要它是 7 位干净的 ASCII,我不会转换首先到 Base-64。只需将其作为二进制数据传输 - 您的代码在时间和带宽上都会更简单、更高效。

【讨论】:

一个完整的文件可能已经通过一个未正常关闭的连接发送(因此被视为一个不完整的文件) @jgauffin:我相信 TCP 会指出这两者之间的区别,并且客户端库(比如 Java 或 .NET)会相应地抛出异常。无论如何,这是我的理解。 只需设计您的应用程序级协议。例如,发送文件信息头,其中包含文件大小,然后是文件内容。如果服务器没有完全接收到文件(例如客户端断开连接),则服务器将文件视为“未完成”。 @JonSkeet:是的,但我的经验是,开发人员将异常视为异常,而不是正常但未正确关闭的事情。我只是说解决方案是可能的,但没有什么值得推荐的。正如您所说,第三个选项是最可靠的方法。 @jgauffin:如果我使用第一种方法,那么您必须那样对待它。我也更喜欢第三种方法,但由于现有协议(例如没有内容长度的 HTTP 1.0。【参考方案2】:

您可以先发送您要发送的字节数。接收端先读取这个,然后知道未来会有多少字节。

例如,您对文件进行编码并确定编码大小为 800 字节。你发送数字 800(比如说,四个字节),然后是文件。

接收方读取四个字节,得到数字 800,然后知道再读取 800 个字节来接收整个文件。

这称为长度前缀。

【讨论】:

以上是关于为啥我的socket接收大数据的时候接收不完全的主要内容,如果未能解决你的问题,请参考以下文章

Socket编程,为啥客户端无法接收来自服务器的数据?

我在用STM32串口DMA接收数据时,为啥在接收过程中,我的程序停止运行了,接收完成后又开始运行,求解?

C# Socket 如何完全发送/接收数据

我写了一个socket server的程序 为啥客户端只能运行一次,而且数据也传不到客户端

python-- Socket接收大数据

Socket通信数据接收的时候不全,导致json解析失败。