socket编程中的接收数据丢失问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket编程中的接收数据丢失问题相关的知识,希望对你有一定的参考价值。

参考技术A 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) .......
........

linux网络编程中阻塞和非阻塞socket的区别

参考技术A 读操作
对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返
回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲
区中的数据大于期望读取的字节数时,读取期望读取的字节数,返回实际读取的长度。
对于非阻塞socket而言,socket的接收缓冲区中有没有数据,read调用都会立刻返回。接收缓冲区中有
数据时,与阻塞socket有数据的情况是一样的,如果接收缓冲区中没有数据,则返回错误号为
EWOULDBLOCK,
表示该操作本来应该阻塞的,但是由于本socket为非阻塞的socket,因此立刻返回,遇到这样的情况,可
以在下次接着去尝试读取。如果返回值是其它负值,则表明读取错误。
因此,非阻塞的rea调用一般这样写:
if
((nread
=
read(sock_fd,
buffer,
len))
<
0)

if
(errno
==
EWOULDBLOCK)

return
0;
//表示没有读到数据
else
return
-1;
//表示读取失败
else
return
nread;读到数据长度
写操作
对于写操作write,原理是类似的,非阻塞socket在发送缓冲区没有空间时会直接返回错误号EWOULDBLOCK,
表示没有空间可写数据,如果错误号是别的值,则表明发送失败。如果发送缓冲区中有足够空间或者
是不足以拷贝所有待发送数据的空间的话,则拷贝前面N个能够容纳的数据,返回实际拷贝的字节数。
而对于阻塞Socket而言,如果发送缓冲区没有空间或者空间不足的话,write操作会直接阻塞住,如果有
足够空间,则拷贝所有数据到发送缓冲区,然后返回.
非阻塞的write操作一般写法是:
int
write_pos
=
0;
int
nLeft
=
nLen;
while
(nLeft
>
0)

int
nWrite
=
0;
if
((nWrite
=
write(sock_fd,
data
+
write_pos,
nLeft))
<=
0)

if
(errno
==
EWOULDBLOCK)

nWrite
=
0;
else
return
-1;
//表示写失败

nLeft
-=
nWrite;
write_pos
+=
nWrite;

return
nLen;
建立连接
阻塞方式下,connect首先发送SYN请求道服务器,当客户端收到服务器返回的SYN的确认时,则
connect
返回.否则的话一直阻塞.
非阻塞方式,connect将启用TCP协议的三次握手,但是connect函数并不等待连接建立好才返回,而是
立即返回。返回的错误码为EINPROGRESS,表示正在进行某种过程.
接收连接
对于阻塞方式的倾听socket,accept在连接队列中没有建立好的连接时将阻塞,直到有可用的连接,才返
回。
非阻塞倾听socket,在有没有连接时都立即返回,没有连接时,返回的错误码为EWOULDBLOCK,表示本来应
该阻塞。
无阻塞的设置方法
方法一:fcntl
int
flag;
if
(flag
=
fcntl(fd,
F_GETFL,
0)
<0)
perror("get
flag");
flag
|=
O_NONBLOCK;
if
(fcntl(fd,
F_SETFL,
flag)
<
0)
perror("set
flag");
方法二:ioctl
int
b_on
=
1;
ioctl
(fd,
FIONBIO,
&b_on);

以上是关于socket编程中的接收数据丢失问题的主要内容,如果未能解决你的问题,请参考以下文章

linux网络编程中阻塞和非阻塞socket的区别

linux网络编程中阻塞和非阻塞socket的区别

Java 通过Socket编程 发送和接收数据

如何通过多线程使用socket和pyqt避免数据丢失

从一次Windows网络编程排错经历中得出的一个可靠拆包算法

qt socket编程问题,不能接收数据,懂的帮忙解答一下,谢谢了。