socket recv 无长度域如果检测数据是否收完?

qiang81020 2014-02-27 06:10:24
非阻塞模式下,使用recv,单次收包数据4K,但是在压力测试时,出现可能收不全数据的情况。

我简单模拟了一下这个情况,将服务端返回的数据分两次间隔2秒回发。在我不知道应该收取多少数据的情况下,我如何能判断是否数据收全了?

这个问题折磨我很长时间,不知道怎么搞。求高手解答。
...全文
229 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2014-02-28
  • 打赏
  • 举报
回复
不知道有多少前人掉在TCP Socket send(人多)send(病少)send(财富) recv(人多病)recv(少财富) 陷阱里面啊! http://topic.csdn.net/u/20120210/09/51109ed0-07b9-41f2-b487-a51597f2ca01.html
ouyh12345 2014-02-28
  • 打赏
  • 举报
回复
最好做一个协议,附加上长度
mujiok2003 2014-02-28
  • 打赏
  • 举报
回复
tcp是流, 需要自己提取消息。 无长度域,则需要消息分割符,没有其他选择。
yanran_hill 2014-02-28
  • 打赏
  • 举报
回复
早期的方式是这样:先发送4字节的数据(header),说明后续的发送长度,然后是指定长度的data 需要你自己定义结构 struct data_s { int32 length; unsigned char data[1]; };
qiang81020 2014-02-28
  • 打赏
  • 举报
回复
引用 3 楼 bravery36 的回复:
tcp是流传输,所以不会有“收完”的情况,只能在应用层定义长度,比如说定义定长包头,包头带长度。
难道必须加长度头么?这个也是设计的时候没考虑,现在要加有点麻烦。。。
qiang81020 2014-02-28
  • 打赏
  • 举报
回复
引用 2 楼 thefirstz 的回复:
recv返回的时候,如果出错,判断下errno的值
errno是该加上,但是貌似解决不了问题。。 我现在主要判断不了是否收完数据了
ForestDB 2014-02-28
  • 打赏
  • 举报
回复
假设我是程序,你不告诉我哪里结束,我就会一直读,直到错误。
bravery36 2014-02-27
  • 打赏
  • 举报
回复
tcp是流传输,所以不会有“收完”的情况,只能在应用层定义长度,比如说定义定长包头,包头带长度。
昵称很不好取 2014-02-27
  • 打赏
  • 举报
回复
recv返回的时候,如果出错,判断下errno的值
qiang81020 2014-02-27
  • 打赏
  • 举报
回复

int RecvDataFromHost(int nSockfd, char *pRecvData, int *nRecvDataLen,int iTimeOut)
{
    int rlen = 0, ret, len = 0;
#ifdef RACAL
	int iLengthHeader = 2;
#else
	int iLengthHeader = 0;
#endif
    int nLenSize = 0; 

    fd_set r_fds;
    struct timeval tv;


    if(pRecvData == NULL)
        return -1;

    if(nSockfd <= 0)
	return -2;

    FD_ZERO(&r_fds);
    FD_SET((u_int)nSockfd, &r_fds);

    if(iTimeOut > 0) {

        tv.tv_sec = iTimeOut;
        tv.tv_usec = 0;

        ret = select(nSockfd + 1, &r_fds, NULL, NULL, &tv);
        if (ret <= 0 || !FD_ISSET(nSockfd, &r_fds))
            return -3;

    } else {
        ret = select(nSockfd + 1, &r_fds, NULL, NULL, NULL);//block
        if (ret <= 0 || !FD_ISSET(nSockfd, &r_fds))
            return -4;
    }

	if (0 == iLengthHeader)
	{
		do
		{
			ret = recv(nSockfd, &pRecvData[rlen], 4096, 0);

			if (ret <= 0)
				return -5;

			rlen += ret;

		} while(0 != ret);//循环是我后加上去的,但是如果这样的话,会阻塞回去,单次收包又收不全数据。
	}
	else if (2 == iLengthHeader)
	{
		int iRecvDataLen = -1;
		ret = recv(nSockfd, &pRecvData[rlen], 2, 0);
		if (ret <= 0)
			return -5;
		iRecvDataLen = (unsigned char)pRecvData[0];
		iRecvDataLen = iRecvDataLen << 8 | (unsigned char)pRecvData[1];
		rlen += ret;

		do{
			ret = recv(nSockfd, &pRecvData[rlen], 1024, 0);
			if (ret <= 0)
				return -5;

			rlen += ret;
			iRecvDataLen -= ret;
		} while(iRecvDataLen > 0);
	}

    if((len + nLenSize) > SECBUF_MAX_SIZE)
        return -6;
    
    *nRecvDataLen = rlen;

    return 0;
}

69,369

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧