c# udp 高并发

2013-07-01 22:41:17 mycn027 阅读数 163

服务器端:

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPServer
{
    class Program
    {
        static void Main(string[] args)
        {
            int recv;
            byte[] data = new byte[1024]; 

            //构建TCP 服务器

            //得到本机IP,设置TCP端口号         
            IPEndPoint ipep = new IPEndPoint(IPAddress.Any , 8001);
            Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram , ProtocolType.Udp);

            //绑定网络地址
            newsock.Bind(ipep);

            Console.WriteLine("This is a Server, host name is {0}",Dns.GetHostName());

            //等待客户机连接
            Console.WriteLine("Waiting for a client");

            //得到客户机IP
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)(sender);
            recv = newsock.ReceiveFrom(data, ref Remote);
            Console .WriteLine ("Message received from {0}: ", Remote.ToString ());
            Console .WriteLine (Encoding .ASCII .GetString (data ,0,recv ));

            //客户机连接成功后,发送欢迎信息
            string welcome = "Welcome ! ";

            //字符串与字节数组相互转换
            data  = Encoding .ASCII .GetBytes (welcome );

            //发送信息
            newsock .SendTo (data ,data.Length ,SocketFlags .None ,Remote );
            while (true )
            {
                data =new byte [1024];
                //发送接受信息
                recv =newsock.ReceiveFrom(data ,ref Remote);
                Console .WriteLine (Encoding .ASCII .GetString (data ,0,recv));
                newsock .SendTo (data ,recv ,SocketFlags .None ,Remote );
            }
        }

    }
}

 客户端:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace UDPClient
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] data = new byte[1024];
            string input ,stringData;

            //构建TCP 服务器

            Console.WriteLine("This is a Client, host name is {0}", Dns.GetHostName());

            //设置服务IP,设置TCP端口号
            IPEndPoint ipep = new IPEndPoint(IPAddress .Parse ("127.0.0.1") , 8001);

            //定义网络类型,数据连接类型和网络协议UDP
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

            string welcome = "Hello! ";
            data = Encoding.ASCII.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ipep);
            IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            EndPoint Remote = (EndPoint)sender;

            data = new byte[1024];
            //对于不存在的IP地址,加入此行代码后,可以在指定时间内解除阻塞模式限制
            //server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);
            int recv = server.ReceiveFrom(data, ref Remote);
            Console.WriteLine("Message received from {0}: ", Remote.ToString());
            Console.WriteLine(Encoding .ASCII .GetString (data,0,recv));
            while (true)
            {
                input = Console .ReadLine ();
                if (input =="exit")
                    break ;
                server .SendTo (Encoding .ASCII .GetBytes (input ),Remote );
                data = new byte [1024];
                recv = server.ReceiveFrom(data, ref Remote);
                stringData = Encoding.ASCII.GetString(data, 0, recv);
                Console.WriteLine(stringData);
            }
            Console .WriteLine ("Stopping Client.");
            server .Close ();            
        }

    }
}

 

2008-08-29 16:57:00 yuechao20022 阅读数 890
 因为要写一个网络程序要用到UDP协议,UDP这东西比较麻烦,又不像TCP一样提供可靠的连接,发送接收的超时实在不好设计,最后只要用Timer来检测有没有想要的数据包-_#,不过这不是这次的重点,重点是怎么建立一种高效的UDP机制来实时接收服务器发送过来的数据包.
     CodeProject上有个例子是开个线程去同步接收,这样倒是可以满足我的程序需求,不过实际中遇到几个问题:

     
1.程序开销大,内存狂飙,接一次数据就要重新开一次线程

     
2.由于主界面和底层是完全隔离只是通过中间的接口来通讯,导致线程总是不能正常的结束,程序结束后还有一个进程在那里不知道干什么.

     于是翻阅MSDN,查找自己以前写的代码,最后还是决定用异步来接收,MSDN上UDP异步的例子不太好,有点敷衍的意思,用异步很好的解决了以上的问题,高效完成效率,代码如下: 
  1. UdpClient qq_client;    //Udp客户端
  2. qq_client = new UdpClient();
  3. IPEndPoint remoteQQEP = new IPEndPoint(remotehost, remoteport);
  4. qq_client.Connect(remoteQQEP);
  5. AsyncCallback GetRecvBuffer = new AsyncCallback(ReceiveCallback);
  6. qq_client.BeginReceive(GetRecvBuffer, null);   
  7. 这里用一个GetRecvBuffer的回掉来实现异步
  8.         private void ReceiveCallback(IAsyncResult ar)
  9.         {
  10.             try
  11.             {
  12.                 lock (this)
  13.                 {
  14.                     byte[] recvbytes = qq_client.EndReceive(ar, ref remoteQQEP);
  15.                     //QQFunction.DebugDump(recvbytes);
  16.                     if (recvbytes[0] != QQDef.QQ_IM_HEAD && recvbytes[0] != 0x03)
  17.                     {
  18.                         //非QQ数据包
  19.                         return;
  20.                     }
  21.                     switch (Pop16(recvbytes, 3))
  22.                     {
  23.                         case QQDef.QQ_REQUEST_TOKEN:
  24.                             DoGetToken(recvbytes);
  25.                             break;
  26.                         case QQDef.QQ_REQUEST_LOGIN:
  27.                             DoGetLogin(recvbytes);
  28.                             break;
  29.                         case QQDef.QQ_GET_ONLINE_FRIEND:
  30.                             DoGetOnline(recvbytes);
  31.                             break;
  32.                         case QQDef.QQ_KEEP_ALIVE:
  33.                             CheckAlive(recvbytes);
  34.                             break;
  35.                         case QQDef.QQ_SEND_IM_MSG:
  36.                             // Do SomeThing
  37.                             break;
  38.                         case QQDef.QQ_RECV_IM_MSG:
  39.                             DoRecvMsg(recvbytes);
  40.                             break;
  41.                         default:
  42.                             QQFunction.DebugDump("UnKnow Command");
  43.                             QQFunction.DebugDump(recvbytes);
  44.                             break;
  45.                     }
  46.                     
  47.                 }
  48.                 lock (this)
  49.                 {
  50.                     AsyncCallback GetRecvBuffer = new AsyncCallback(ReceiveCallback);
  51.                     qq_client.BeginReceive(GetRecvBuffer, null);
  52.                 }
  53.             }
  54.             catch
  55.             {
  56.             }
  57.         }

 

代码是不是很简单?功能是不是很强大?

2016-08-22 17:23:00 weixin_30411239 阅读数 232

c# udp

2018-08-15 14:48:14 qq_39097425 阅读数 983

1.接收

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            UdpClient client = null;
            string receiveString = null;
            byte[] receiveData = null;
            //实例化一个远程端点,IP和端口可以随意指定,等调用client.Receive(ref remotePoint)时会将该端点改成真正发送端端点 
            IPEndPoint remotePoint = new IPEndPoint(IPAddress.Any, 0);

            while (true)
            {
                // u3d接收端口
                client = new UdpClient(9000);
                receiveData = client.Receive(ref remotePoint);//接收数据 
                receiveString = Encoding.Default.GetString(receiveData);
                Console.WriteLine(receiveString);
                client.Close();//关闭连接 
            }
        }
    }
}

 

2.发送

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UdpClientNa
{
    class Program
    {
        static void Main(string[] args)
        {
            string sendString = null;//要发送的字符串 
            byte[] sendData = null;//要发送的字节数组 
            UdpClient client = null;

            IPAddress remoteIP = IPAddress.Parse("127.0.0.1"); //假设发送给这个IP
            // u3d发送端口 9000是发送端口
            int remotePort = 9000;
            IPEndPoint remotePoint = new IPEndPoint(remoteIP, remotePort);//实例化一个远程端点 

            while (true)
            {
                sendString = Console.ReadLine();
                sendData = Encoding.Default.GetBytes(sendString);

                client = new UdpClient();
                client.Send(sendData, sendData.Length, remotePoint);//将数据发送到远程端点 
                client.Close();//关闭连接 
            }
        }
    }
}

 

2016-05-02 20:08:50 ljlstart 阅读数 11436

大多数UDP服务器程序是迭代运行的,服务器等待一个客户请求,读入这个请求,处理这个请求,送回其应答,再等待下一个客户请求。

然而当客户请求的处理需要消耗过长的时间时,我们期望UDP服务器程序具有某种形式的并发性。

当使用TCP时,服务器的并发处理得以简化的根源在于每个客户连接都是唯一的(不同的已连接套接字),标识每个客户连接的是一个唯一的套接字对。

然而当使用UDP时,服务端通过同一个套接字和所有的客户端进行通信,当采用并发模式时,每一个子进程共享同一个UDP套接字,因此无法简单地绑定于一个客户并为其服务。


有两种情况下可以使用并发的UDP服务器:

1 读入一个客户请求并发送一个应答后,与这个客户不再有任何联系。在这种情形下,当一个UDP请求到达时,阻塞在epoll_wait调用上的父进程被唤醒,然后fork一个子进程去调用recv_from读取一个请求(一个完整的数据报),处理完该请求后再调用send_to发送回去。

2  第二种UDP服务器与客户交互多个数据报。问题在于每个客户都是往服务器端的同一个的端口发送数据。并发服务器的每一个子进程如何正确区分每一个客户的数据报(涉及到进程的调度问题,如何避免一个子进程读取到不该它服务的客户发送来的数据报)。解决的方法是为每个客户创建一个的新的套接字,在其上bind一个临时端口,fork一个子进程使用该套接字发送对该客户的所有应答。这个办法要求客户查看服务器第一个应答的中的源端口号,并把本请求的后续数据报发送到该端口。