免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4074 | 回复: 5
打印 上一主题 下一主题

UDP通信的同步问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-09-18 18:43 |只看该作者 |倒序浏览
我有个奇怪(或许是幼稚)的问题,UDP连接通信,自定义了数据包,并且有最大包长,
如果某个包丢了一段数据,导致包尾包括了下一包的包头,怎么办?怎么重新同步?

我曾想过用一个固定包头前缀(如"abc")来获得下一个包的头部,但是这个包头前缀有可能和包内容相同,
也会有问题,至少在理论上是有问题的,而如果把包数据中和包头前缀相同的增加转义字符(如"\a\b\c")
来区分,但这样开销太大,怎么办?

论坛徽章:
0
2 [报告]
发表于 2008-09-18 22:14 |只看该作者
记得UDP好像不会粘包,只会丢包~

论坛徽章:
0
3 [报告]
发表于 2008-09-18 22:46 |只看该作者
原帖由 spren 于 2008-9-18 18:43 发表
我有个奇怪(或许是幼稚)的问题,UDP连接通信,自定义了数据包,并且有最大包长,
如果某个包丢了一段数据,导致包尾包括了下一包的包头,怎么办?怎么重新同步?

我曾想过用一个固定包头前缀(如"abc")来 ...


包丢了,重发啊。

论坛徽章:
0
4 [报告]
发表于 2008-09-19 08:50 |只看该作者
谢谢,我的意思是说UDP上层应用程序接收一个数据包(是自定义的UDP之上的一个包),包头带有包长度,
但是如果接收了包头后,包数据的一段数据(可能是一个UDP包)传输过程中丢了,有什么好的重同步方法?

论坛徽章:
0
5 [报告]
发表于 2008-09-24 18:30 |只看该作者
调研之后的结论,不对的地方请指正:
对于sendto并且是UDP socket,如果没有指定MSG_MORE等标识,一个sendto命令发送的数据包将封装在一个UDP包里面发送,如果包太长则返回失败并且不会发送任何字节的数据。在Ip层,udp有可能被分包和组合,但是在接收端一定是以发送时的包格式呈现,除非接收函数recvfrom提供的缓存区不够大(这种情况怎么处理我还不确定)。因此udp包要丢就丢整个包,并且传输成功的udp包之间可能是乱序的。

调用关系如下:
sendto(int  s,  const  void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)
==>sys_sendto(int fd, void __user *buff, size_t len,unsigned flags, struct sockaddr __user *addr,int addr_len)
==>sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
==> __sock_sendmsg(&iocb, sock, msg, size)
==> sock->ops->sendmsg(iocb, sock, msg, size)
==>udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,size_t len)
==>udp_push_pending_frames(sk)
==>ip_push_pending_frames(sk)
==>ip_local_out(skb)
==>dst_output(skb)
==>skb->dst->output(skb)



部分内核代码:
================
535int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
536                size_t len)
537{
538        struct inet_sock *inet = inet_sk(sk);
539        struct udp_sock *up = udp_sk(sk);
540        int ulen = len;

            //是否组合数据包
549        int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;

552        if (len > 0xFFFF)
553                return -EMSGSIZE;
554

579        ulen += sizeof(struct udphdr);

693        /*
694         *      Now cork the socket to pend data.
695         */
696        inet->cork.fl.fl4_dst = daddr;
697        inet->cork.fl.fl_ip_dport = dport;
698        inet->cork.fl.fl4_src = saddr;
699        inet->cork.fl.fl_ip_sport = inet->sport;
700        up->pending = AF_INET;
701
702do_append_data:
703        up->len += ulen;
704        getfrag  =  is_udplite ?  udplite_getfrag : ip_generic_getfrag;
705        err = ip_append_data(sk, getfrag, msg->msg_iov, ulen,
706                        sizeof(struct udphdr), &ipc, rt,
707                        corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
708        if (err)
709                udp_flush_pending_frames(sk);
710        else if (!corkreq)
711                err = udp_push_pending_frames(sk);
712        else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
713                up->pending = 0;
714        release_sock(sk);
715

================
1207/*
1208 *      Combined all pending IP fragments on the socket as one IP datagram
1209 *      and push them out.
1210 */
1211int ip_push_pending_frames(struct sock *sk)
1212{

1288        /* Netfilter gets whole the not fragmented skb. */
1289        err = ip_local_out(skb);

================
104int ip_local_out(struct sk_buff *skb)
105{
106        int err;
107
108        err = __ip_local_out(skb);
109        if (likely(err == 1))
110                err = dst_output(skb);
111
112        return err;
113}

================
234/* Output packet to network from transport.  */
235static inline int dst_output(struct sk_buff *skb)
236{
237        return skb->dst->output(skb);
238}
239

================
  94int __ip_local_out(struct sk_buff *skb)
  95{
  96        struct iphdr *iph = ip_hdr(skb);
  97
  98        iph->tot_len = htons(skb->len);
  99        ip_send_check(iph);
100        return nf_hook(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, skb->dst->dev,
101                       dst_output);
102}

================
147/**
148 *      nf_hook_thresh - call a netfilter hook
149 *      
150 *      Returns 1 if the hook has allowed the packet to pass.  The function
151 *      okfn must be invoked by the caller in this case.  Any other return
152 *      value indicates the packet has been consumed by the hook.
153 */
154static inline int nf_hook_thresh(int pf, unsigned int hook,
155                                 struct sk_buff *skb,
156                                 struct net_device *indev,
157                                 struct net_device *outdev,
158                                 int (*okfn)(struct sk_buff *), int thresh,
159                                 int cond)
160{
161        if (!cond)
162                return 1;
163#ifndef CONFIG_NETFILTER_DEBUG
164        if (list_empty(&nf_hooks[pf][hook]))
165                return 1;
166#endif
167        return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
168}
169
170static inline int nf_hook(int pf, unsigned int hook, struct sk_buff *skb,
171                          struct net_device *indev, struct net_device *outdev,
172                          int (*okfn)(struct sk_buff *))
173{
174        return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN, 1);
175}

论坛徽章:
0
6 [报告]
发表于 2008-09-24 19:56 |只看该作者
tcp/ip详解 系列都有讲到
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP