UDP编程实验

        最近基于SNMP网络管理协议开发网管软件,SNMP协议传输层为UDPport 161162),网络上流行的C#SNMP封装库SnmpSharpNet似乎不能够支持大规模(400台以上)网络设备管理,因为对udp通信模型封装的不够好。SnmpSharpNet虽然支持异步(AsyncUDP传输,但是在业务上了利用_busy变量限制了发送接收同时并发的可能。

        高性能的UDP传输,起码应该是多线程并发的,即多线程同时发送,多线程同时接收。本人对UDP编程的一些函数有些疑问,特做实验求解:

1>     ReceiveFrom,作为阻塞模式,到底阻塞多久?

2>     多线程同时SendTo,可行吗?

3>     多线程同时ReceiveFrom,可行吗?

4>     connect作用?

5>     再多线程同时send

6>     再多线程同时receive

1.        ReceiveFrom

A.设置等待时间:_socket.SetSocketOption(SocketOptionLevel.Socket,

SocketOptionName.ReceiveTimeout, timeout);只要在timeout ms时间内,收到数据,程序立刻往下执行;否则timeout ms后,程序甩SocketException中的超时异常。

B.此函数每执行一次,只接收一个UDP数据包。

C.使用UDP编程,一般应用程序需要实现超时重传,即多长时间未收到响应请求的数据包,再次发送请求。注意某种情况:请求命令11次,超时,请求命令12次,读到命令1响应,处理;请求命令21次,读到命令响应,这个响应可能是上次命令1的响应,也可能是此次命令2的响应,要解包分析。

2.        多线程同时SendTo

3.        多线程同时ReceiveFrom

实验1

        服务器SendTo发送请求,客户机ReceiveFrom,客户机接着SendTo,服务器ReceiveFrom返回响应,局域网耗时15ms(程序另有一些Console.WriteLineDateTime.Now.ToString函数调用)。两台服务器对同一个客户端通信,没出现数据包发错,肯能是服务器数量还不够?

实验2

        在服务端,把SendToReceiveFrom封装到一个函数Request中,启动三个线程,同时调用Request发送不同的数据请求。

                Thread1_Request(“1234567890ab”);              //回送 2234567890ab

                Thread2_Request(“abcefg123”);                    //回送 bbcefg123

                Thread3_Request(“abc987123”);                   //回送 bbc987123

        接收端在接收到数据后,把首个字符+1,发送回服务器。我们希望同一线程中请求与响应的数据包对应,很遗憾,实际多线程接收时,线程2可能ReceiveFrom线程3的响应。如下所示一次3个线程并发过程:

Thread2       21:24:24.156接收:bbcefg123

Thread3       21:24:24.156接收:bbc987123

                      21:24:24.156接收:2234567890ab

Thread3       21:24:24.156接收:bbcefg123                //不是期望数据包

Thread2       21:24:24.156接收:bbc987123               //不是期望数据包

                       21:24:24.156接收:2234567890ab

Thread2       21:24:24.171接收:bbcefg123

Thread3       21:24:24.171接收:bbc987123

                      21:24:24.171接收:2234567890ab

Thread2       21:24:24.187接收:bbcefg123

Thread3       21:24:24.187接收:bbc987123

                      21:24:24.187接收:2234567890ab

Thread3      21:24:24.187接收:bbc987123

                     21:24:24.203接收:2234567890ab

Thread2     21:24:24.203接收:bbcefg123

Thread2     21:24:24.375接收:bbcefg123

Thread3     21:24:24.375接收:bbc987123

                    21:24:24.375接收:2234567890ab

                    21:24:24.375接收:2234567890ab

Thread3     21:24:24.375接收:bbc987123

Thread2     21:24:24.375接收:bbcefg123

Thread2     21:24:24.390接收:bbc987123               //不是期望数据包

Thread3     21:24:24.390接收:bbcefg123                //不是期望数据包

                    21:24:24.390接收:2234567890ab

        经实验得出:一台服务器多线程同时对一台客户端通信,客户端响应服务器请求的数据包,在服务器接收时,同一线程的请求与响应会不对应,即本地UDP接收,谁先ReceiveFrom,接收区的数据包就被谁取走,而不管哪个请求的。

        UDP模式下,多线程通信是,SendToReceiveFrom不能同时封装在一个线程内,应该有独立的ReceiveFrom接收线程,对每次ReceiveFrom的数据包解析,从业务上识别出是对哪次SendTo请求的回应。如果发送、接收封装在同一个线程,超时重传机制容易实现,但是只能单线程通信了,大规模采集通信情况下满足不了。如果发送、接收各个独立线程,采集通信就可并发了,然而响应包是哪个请求、超时重传机制实现麻烦一些。

实验3

        单服务器单线程与通信客户端通信,服务器端线程代码如下:

while (true)

{

    try

    {

        ++moniNum;

        _socket.SendTo(buffer, bufferLength, SocketFlags.None, (EndPoint)netPeer);

         sw.Start();

         Console.WriteLine("执行{0}次,时间:{1}", moniNum,DateTime.Now.ToString(("HH:mm:ss.fff")));

recv = _socket.ReceiveFrom(inbuffer, ref remote);

         sw.Stop();

         Console.WriteLine("{1}执行此段代码耗时:{0} ms", sw.ElapsedMilliseconds, moniNum);

    }

    catch (SocketException ex)

    {}

   if (recv > 0)

    {

          sw.Stop();

       Console.WriteLine("{1}成功接收耗时:{0} ms", sw.ElapsedMilliseconds, moniNum);

    }

}

        客户端ReceiveFrom监听,一收到数据马上SendTo回给服务器。

运行结果如下:

执行1次,时间:09:39:30.656

1执行此段代码耗时:75 ms                  //75ms

1成功接收耗时:75 ms

执行1次,时间:09:39:30.734

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

执行1次,时间:09:39:30.734

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

执行1次,时间:09:39:30.734

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

执行1次,时间:09:39:30.734

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

执行1次,时间:09:39:30.734

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

执行1次,时间:09:39:31.156

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

执行1次,时间:09:39:31.156

1执行此段代码耗时:196 ms                 //196ms

1成功接收耗时:196 ms

执行1次,时间:09:39:31.343

1执行此段代码耗时:0 ms

1成功接收耗时:0 ms

疑问:为什么服SendTo->客ReceiveFrom->客SendTo->服Receive过程有大量的耗时0ms?有那么快吗?即使sw.Start()语句放在服SendTo之前,也是如此。

实验4

        服务器单线程封装SendToReceiveFrom,线程中SendTo轮询各个客户端,ReceiveFrom各个客户端的响应。客户端监听线程ReceiveFrom数据后,立刻SendTo至服务器。

        服务器期望:任意客户端ReceiveFrom的数据包是对其上一次SendTo的响应。

        但是,如果服务器请求客户端1数据,超时,重发,还是超时,最后超时次数已过,服务器接着请求客户端2的数据,等待客户端2的回复,然而,如果这时收到了客户端1的UDP数据包,ReceiveFrom接收后,丢弃此包。本来等待客户2的ReceiveFrom机会,错过了。按程序,再次对客户2执行SendTo和ReceiveFrom。这有几个问题:A.其实没必要对客户2再次SendTo;B.如果对客户2再次SendTo了,它会回复两次,那么这两次又有一次会成为后面处理的多余负担;C.那么好点的方案应该是ReceiveFrom与SendTo分离,不绑定在同一个线程内;D.方案C有前提,准备接收客户2的回复时,无法对UDP接收区清除(能,这也还不够),超时后,网络再也不可能收到此次请求的回复数据包。

4.        connect作用

5.        再多线程同时send

6.        再多线程同时receive

你可能感兴趣的:(UDP编程实验)