Chinaunix

标题: 关于TCP有序传输的问题 [打印本页]

作者: 问号    时间: 2003-02-17 18:23
标题: 关于TCP有序传输的问题
假设有2个字符串A,B,通过2次send发送出去,在接收端用recv接收。假设recv一次不能完全接受A字符串的全部内容,可能为N次,那么我想问一下,在第一次调用recv接收到部分A字符串,第二次调用recv接受的内容肯定是A字符串的么?会不会是B字符串的内容?请大家指教。

这个问题我还搞不清楚,看书上说,TCP协议可以保证数据的有序传输,也就是说我使用send发送内容,recv肯定能完整无错的收到。但是我使用了nonblock的recv,recv会马上返回,不管接收到多少数据,也就是说可能只收到部分的内容,就返回了,我还要自己判断,继续调用recv,直到全部接收。不知道以上我的理解时候正确,请大家指正其中的错误,谢谢:)
作者: 无双    时间: 2003-02-17 19:21
标题: 关于TCP有序传输的问题
不一定
就是说你send了几次
并不是一定会recv几次
可能一次收到所有

也可能用更多次数收才能收完

这种问题一般在发送前先发送一个长度字符表示自己想发送的内容的长度

然后再发内容

接收时先接收长度
再根据长度接收指定长度的内容


一般可以用一个short表示自己想发的长度
作者: 问号    时间: 2003-02-17 20:57
标题: 关于TCP有序传输的问题
对,我就是这么做的,在消息头用一个short定义长度,最坏的可能就是一次只收到1个字节,那么就不知道这条消息的具体长度了。撇开这个不说。

接受消息,在internet上,一次收到所有的消息倒不是大问题,最大的问题就在于一次发送,多次接受。我想斑竹可能没完全理解我第一个问题,我的问题是:

字符串A AAAAAAAAAA
字符串B BBBBBBBBBB

然后使用send,先后发送字符串A和B。

接收端第一次使用recv,收到内容AAAAA,那么请问,第二次使用recv,会不会收到B打头的内容,是不是要等到收到全部的A只有,才会收到B打头的内容?

我搞不清楚,谢谢:)
作者: flw    时间: 2003-02-17 23:26
标题: 关于TCP有序传输的问题
就是,TCP 绝对保证有序。如果是先发送 A,再发送 B 的话,那么肯定是先收到 A,再收到 B ---- 尽管 A 不一定一次收到。
作者: 问号    时间: 2003-02-18 00:28
标题: 关于TCP有序传输的问题
谢谢,刚才在路上我也在琢磨。一旦建立了通道,就好像两条单车道的路,同向行驶,先出发的一般先到,后出发的后到。不过我还是要再看看TCP/IP vol1,还有好多要学啊:)
作者: 无双    时间: 2003-02-18 08:35
标题: 关于TCP有序传输的问题
我的意思就是说
如果是用short表示长度的话
那么选
short len;
if recv(socketid,len,2)!=2  //选接收长度
    return error;

再根据长度接收内容
以下是以前写的例子

  1. // ---------------------------------------------------------------------------------------------
  2. //                从端口中读入数据包 包格式为:
  3. //                        前两个字节是包长度,后面是包内容//                param:
  4. //                Param:
  5. //                        Socketid, target user socket id
  6. //                        Msg:                the char buf to save the recv info
  7. //                        msglen:        the char buf length,to prevent buf over flow
  8. //                        Sec                :the time whhile wait for the msg
  9. //                returnL        -1        socket error,
  10. //                                >;0   the msg recv
  11. // ---------------------------------------------------------------------------------------------
  12. int TcpCommClass::RecvPackage (const int SocketId, char *Msg,const int MsgLen) const
  13. {
  14.   fd_set FDSet;
  15.   TIMEVAL TimeVal;

  16.   TimeVal.tv_sec = RecvTimeout;
  17.   TimeVal.tv_usec = 0;

  18.   FD_ZERO (&FDSet);
  19.   FD_SET (SocketId, &FDSet);

  20.   if (select (0, &FDSet, NULL, NULL, &TimeVal) != 1)
  21.     return -1;

  22.   short recvlen,recvcount=0;
  23.   if(recv (SocketId, (char*)&recvlen, 2, 0)!=2)
  24.           return -1;

  25.   if(recvlen>;=MsgLen||recvlen<=0)
  26.           return -1;

  27.   memcpy(Msg,&recvlen,2);

  28.   while(recvcount<recvlen){
  29.   TimeVal.tv_sec = 1;
  30.   TimeVal.tv_usec = 0;

  31.   FD_ZERO (&FDSet);
  32.   FD_SET (SocketId, &FDSet);
  33.   
  34.   if (select (0, &FDSet, NULL, NULL, &TimeVal) != 1)
  35.     return -1;
  36.   
  37.    recvcount+=recv(SocketId,Msg+2+recvcount,recvlen-recvcount,0);
  38.   }
  39.   return recvcount;
  40. }

复制代码

作者: 无双    时间: 2003-02-18 08:35
标题: 关于TCP有序传输的问题
发送的例子

  1. // ---------------------------------------------------------------------------------------------
  2. //                从端口中读入消息,先写两个字节作消息长度再写消息内容
  3. //                        Socketid        :        the target socket
  4. //                        msg                :        the message want to send
  5. //                        msglen        :        how many chars you want to send,if =-1 the send all in the string
  6. //                        sec                :        how many time wait for send
  7. //                return:
  8. //                        true                send success.        false:        send fail
  9. // ---------------------------------------------------------------------------------------------
  10. bool TcpCommClass::SendPackage (const int SocketId, const char *Msg,const int MsgLen) const
  11. {
  12.   fd_set FDSet;
  13.   TIMEVAL TimeVal;

  14.   TimeVal.tv_sec = SendTimeout;
  15.   TimeVal.tv_usec = 0;

  16.   FD_ZERO (&FDSet);
  17.   FD_SET (SocketId, &FDSet);

  18.   if (select (0, NULL, &FDSet, NULL, &TimeVal) != 1)
  19.     return false;

  20.   short sendlen =MsgLen == -1? strlen (Msg):MsgLen;

  21.   if(send(SocketId,(char*)&sendlen,2,0)!=2)
  22.           return false;

  23.   TimeVal.tv_sec = 1;
  24.   TimeVal.tv_usec = 0;

  25.   FD_ZERO (&FDSet);
  26.   FD_SET (SocketId, &FDSet);

  27.   if (select (0, NULL, &FDSet, NULL, &TimeVal) != 1)
  28.     return false;
  29.   return send (SocketId, Msg, sendlen, 0) == sendlen;
  30. }

复制代码

作者: 问号    时间: 2003-02-18 11:10
标题: 关于TCP有序传输的问题
看了你的代码,获益非浅,不过有些问题,比如,发送端正确发送了长度消息和真正的消息,而接收端一次接收,只收到了1个字节,那么就意味着发送端发送的这一组消息都作废了.

我想是不是因为以上的代码是最简单的,没有考虑任何出错判断呢?
作者: 无双    时间: 2003-02-18 12:57
标题: 关于TCP有序传输的问题
没有考虑那么多
因为一次发送两个字节
并接收两个总是成功的
不会多次发送
也不需要多次接收

所以我不想把代码写得那么麻烦

而且以上代码在实际应用中也没有出过问题
(当然也是因为在局域网内带宽是100M)

如果你想改进也可以
作者: 问号    时间: 2003-02-18 14:28
标题: 关于TCP有序传输的问题
对,考虑的问题的确很少,我现在是在广域网环境里面,就必须要考虑到最坏情况,就是接收到1字节的情况,还有就是同时接收到一堆消息的情况。
作者: gadfly    时间: 2003-02-18 15:23
标题: 关于TCP有序传输的问题
1字节问题,那你就做多次接受。

同时收到多个消息,需要你自己定义应用报文的协议格式,接受方对数据做解析。
作者: flw    时间: 2003-02-18 21:31
标题: 关于TCP有序传输的问题
[quote]原帖由 "问号"]不过有些问题,比如,发送端正确发送了长度消息和真正的消息,而接收端一次接收,只收到了1个字节,那么就意味着发送端发送的这一组消息都作废了.[/quote 发表:

我晕!
作者: 问号    时间: 2003-02-18 23:34
标题: 关于TCP有序传输的问题
[quote]原帖由 "问号"]对,考虑的问题的确很少,我现在是在广域网环境里面,就必须要考虑到最坏情况,就是接收到1字节的情况,还有就是同时接收到一堆消息的情况。[/quote 发表:


重新考虑了一下,这是我比较笨的表现了 我的新想法是在客户连接服务器后,马上发送一个同步消息,服务器收到后马上给客户端一个反馈,客户端收到后,就表示双方可以发送消息了,接下来只要写一个比较好的消息解释就可以。

然后,客户端定时或者定量的发送一次同步消息,避免网络传输中的错误,放弃一部分错误的消息,重新开始。

大家看看,觉得我这个方法还可以吧
作者: flw    时间: 2003-02-19 00:56
标题: 关于TCP有序传输的问题
楼上的这位大哥!你以为 TCP 是干啥吃的?你说的这些工作 TCP 早就替你做了!
要是在 UDP 下倒是可以试一下。
作者: 问号    时间: 2003-02-21 01:52
标题: 关于TCP有序传输的问题
这个我当然知道。不过现在的问题就是,我现在使用非阻塞的段口,recv会立即返回,不管收到多少,不能保证一次就能收到对方send过来的全部内容,所以我认为必须在上一层做一个接受缓存的判断处理。

至于之前我说的同步信息,的确不需要了。

如果我还在钻牛角尖的话,请告诉我,谢谢:)
作者: 无双    时间: 2003-02-21 09:17
标题: 关于TCP有序传输的问题
那你可以使用一个接收缓冲区

并有一个专门的接收线程

接收线程把接收到的内容放到接收缓冲区

其它函数从接收缓冲区读就是
作者: nile    时间: 2003-02-21 17:05
标题: 关于TCP有序传输的问题
我来总结一下:

1: Server A send 的所有内容都保存在Server B 的Buffer 中(当然有长度限制)。

2: Server B 上的Recv nonblock 顺序读取Buffer 中的内容。不管你怎么Recv. 都是一个一个接着读。

3: 正常情况下, 不会有数据在网络传输时丢失。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2