免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4449 | 回复: 5

传递变长结构体,用TCP好还是用UDP好? [复制链接]

论坛徽章:
0
发表于 2012-06-18 22:39 |显示全部楼层
大家好!有个问题想请教下各位高手:
在Linux下,我用socket做了一个进程间通信的接口,想传一个变长结构体(可能很长),用TCP好还是用UDP好?
(1)若用UDP(SOCK_DGRM)传,变长结构体的长度大于包的长度怎么办?(UDP的消息队列中,包的最大长度是固定)
(2)若用TCP(SOCK_STREAM),用循环recv()后,将所有数据放到一个buffer中,怎么能保证收到的结构体是完整的?

先谢谢各位了!

另外,
1,TCP传输过程中,recv会不会收到一些除了自己结构体以外的没用数据?
2,UDP传输过程中,recvfrom一次是取一个包吗?

论坛徽章:
0
发表于 2012-06-19 14:12 |显示全部楼层
顶一下自己,我觉得这个问题是基本的,看到很多人的代码直接send(), recv()一下就完事了,可是这样做会不会留下bug?希望有明白的人指点一下。谢谢!

论坛徽章:
0
发表于 2012-06-19 14:28 |显示全部楼层
本帖最后由 fdl19881 于 2012-06-19 14:29 编辑

如果在运输层会超过一个包的最大长度65535的话, 那还是用tcp吧。

使用udp的情况下,会出现丢失,还得自己写确认的代码,且还得自己把包分成多个,然边手动组装。

用tcp的情况 , 接收端没关系, 本来就是字节流。
这种情况的数据格式如下:(参考下)
起始位1B + 数据长度4B(指后面数据部分长度)  + 数据部分 [+ 结束码1B(可要可不要)]

发的时候:1.先按照这个格式把包组装好。
          2. 自己将包拆成每1460字节(以下)全部按顺序使用send发出。
          3. OK.

收的过程:收端得记录收数据的状态: 如:enum {WAITSTART, WAITLEN0 , WAITDATA1 , WAITDATA2, WAITDATA3 , WAITDATA } stat;
       表示当stat == WAITSTART :指等待一个起始数据(你的一个新的结构体)
        stat == WAITLEN##i : 当上一个状态,收到的一个字节与起始位相同时,就转到这个状态。 依次等待4个字节的长度。假设四个字节的长度为n
        stat == WAITDATA: 当上一个状态,收完4个字节的长度信息n时,转到此状态. 继续等待实际的数据部分。 若收完n个字节后,表示收到一个完整的数据,,此时这个结构体就可以拿来使用了。stat接着转入WAITSTART状态。

上面所以说的说到1个字节 ,再一个字节 ,并不是要你使用recv或者read一次只读一个字节,注意这是面向流的。 而是说一次读MAX个字节后,一个个处理.

具我所知的tcp发送时一般可以使用这种方法发送。   至于说万一中间出现一次混乱,那怎么办。我只能说你得好好控制自己的程序,一般只要send或者write是严格按照上面的格式发送。那么tcp又是可靠的情况下,一般是不会出现混乱的。。。 还有一点既然数据部分是结构体,你就检查下这个结构体的信息是否正确。不正确的话,就丢弃吧。准备接下一个

或者为了可靠性,你就在后面再跟上几个字节的检验码吧。(如果真有这个必要)

论坛徽章:
0
发表于 2012-06-19 14:30 |显示全部楼层
tcp要区分出边界信息就加上每次发送的长度信息。

论坛徽章:
1
戌狗
日期:2014-07-17 19:24:40
发表于 2012-06-19 17:47 |显示全部楼层
不求传输性能就用TCP,简单的多。
一般都有一个数据头来描述数据,比如{DataType, DataLen,Result...};
对端首先要接收头,如果接收的长度小于头长度,则继续接受,直到接到的长度超过头长度。
接收到完整的头长度后,就可以根据DataLen计算出后面还需要接收多少数据了,
之后继续接收数据,直到把这个数据接收全了。放入其他队列(线程)处理。
这里要注意的一点是,接收数据时,有可能把下一个的数据头也接收到了。要把接收到的多余的数据保存下来。

论坛徽章:
0
发表于 2012-06-28 22:21 |显示全部楼层
非常感谢楼上两位的的帮助,回答的这么详细,非常感谢!
这两天我也在琢磨这个问题,下面和大家分享一下我的心得,如果说的不对,欢迎指正!
1,可以确定,一般情况下应该用TCP,因为可靠传输能保证数据完整。
2,关于校验问题,TCP本身就有CRC校验,所以有这么一句“TCP传输,收到的即是正确的”
3,对于阻塞模式下,recv(BUFSIZE)/send(BUFSZIE)的返回会有四种可能:
(1)正确返回,返回值等于BUFSIZE;
(2)发送/接受一半时被信号中断,返回值小于BUFSIZE;
(3)阻塞等待时被信号中断,粗错返回-1, errno==EINTR;
(4)出错返回-1.
4,综上,我觉得代码这样写比较保险一些:
len = LEN;
pos = 0;
while(len>0) {
    ret = recv(sd, buf + pos, len, 0);
    if(ret<0) {
           if (errno==EINTR){
                   continue;
           } else {
                  perror("recv()");
                  exit(1);
          }
    } else {
             len -= ret;
              pos += ret;
   }
}
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP