Chinaunix

标题: UDP通信的同步问题 [打印本页]

作者: spren    时间: 2008-09-18 18:43
标题: UDP通信的同步问题
我有个奇怪(或许是幼稚)的问题,UDP连接通信,自定义了数据包,并且有最大包长,
如果某个包丢了一段数据,导致包尾包括了下一包的包头,怎么办?怎么重新同步?

我曾想过用一个固定包头前缀(如"abc")来获得下一个包的头部,但是这个包头前缀有可能和包内容相同,
也会有问题,至少在理论上是有问题的,而如果把包数据中和包头前缀相同的增加转义字符(如"\a\b\c")
来区分,但这样开销太大,怎么办?
作者: Roemer    时间: 2008-09-18 22:14
记得UDP好像不会粘包,只会丢包~
作者: eveson    时间: 2008-09-18 22:46
原帖由 spren 于 2008-9-18 18:43 发表
我有个奇怪(或许是幼稚)的问题,UDP连接通信,自定义了数据包,并且有最大包长,
如果某个包丢了一段数据,导致包尾包括了下一包的包头,怎么办?怎么重新同步?

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


包丢了,重发啊。
作者: spren    时间: 2008-09-19 08:50
谢谢,我的意思是说UDP上层应用程序接收一个数据包(是自定义的UDP之上的一个包),包头带有包长度,
但是如果接收了包头后,包数据的一段数据(可能是一个UDP包)传输过程中丢了,有什么好的重同步方法?
作者: spren    时间: 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}
作者: haofish    时间: 2008-09-24 19:56
tcp/ip详解 系列都有讲到




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