• .NET Socket开发(2) 异步Socket


    在基于.NET的网络服务端的开发中,我们用到和听到的最多的恐怕就是异步Socket了。异步Socket的性能比同步高出很多,但是编写代码比较复杂。因此异步Socket也是网络上讨论比较多的话题。

    今天,我们就来讨论一下如何用异步Socket开发网络应用。在此之前我们先讨论两个问题。

    一、异步Socket是如何工作的:

    那异步Socket是如何工作的呢?我以接收一条消息来说明这个问题。首先,程序向系统投递一个接收数据的请求,并为其指定一个数据缓冲区和回调函数,回调函数用来指示当数据到达后将如何处理,然后我们的程序继续执行下去,当有数据到达的时候,系统将数据读入缓冲区,并执行回调函数,处理这条消息。我们并不需要关心这条消息何时到达。

    二、什么情况下我们用异步Socket

    有些人认为,异步Socket的性能比同步Socket的性能高很多,应该在各种环境下都用异步Socket,其实不然。在某些环境下面。异步反到比同步的性能低,那么在哪些情况下会这样呢?

    1、 客户端Socket

    2、 服务端连接数比较少。

    3、 连接数很多,但都是短连接。

    在这些环境下,我们用同步Socket不但可以简化代码,而且性能并不会比异步Socket低。但在服务端连接比较多而且是长连接的情况下,我们就要使用异步Socket

    现在我们来看看如何用异步Socket编程。

      服务端:

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Net;
    using System.Net.Sockets;

    namespace CutImage
    {
        
    public class MySocket
        {
            Socket _server;
            
    public MySocket()
            {        
                _server 
    = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                _server.Bind(
    new IPEndPoint(IPAddress.Any,8808));
                _server.Listen(
    100);

                Thread th 
    = new Thread(new ThreadStart(WriteConnetion));
                th.Start();
            }
            
    /// <summary>
            
    /// 等待客户端连接的方法
            
    /// </summary>
            void WriteConnetion()
            {
                
    while(true)
                {
                    Socket s 
    = _server.Accept();
                    User user 
    = new User();
                    user.Userid 
    =Guid.NewGuid().ToString();
                    user.mysocket 
    = s;
                    s.BeginReceive(user.msg, 
    0, user.msg.Length, SocketFlags.None, new AsyncCallback(Recivecallback),user);//向系统投递一个接受信息的请求 Recivecallback为回调函数
                }
            }
            
    /// <summary>
            
    /// 接受信息的回调函数
            
    /// </summary>
            
    /// <param name="ar"></param>
             void Recivecallback(IAsyncResult ar)
            {
                User user 
    = (User)ar.AsyncState;
                Socket _customersocket
    =user.mysocket;
                
    int recivecount=0;
                
    try
                {
                     recivecount 
    = _customersocket.EndReceive(ar);
                }
                
    catch (SocketException)//连接断开
                {
                    Close(user);
                }
    catch
                {

                }
                
    if(recivecount>0)
                {
                    
    byte[] buffer = new byte[recivecount];//收到的信息
                    Buffer.BlockCopy(user.msg, 0, buffer, 0, recivecount);
                    GetMsg(user, buffer);
    //这个函数用来处理接收到的信息
                    try
                    {
                        user.mysocket.BeginReceive(user.msg, 
    0, user.msg.Length, SocketFlags.None, new AsyncCallback(Recivecallback), user);
                    }
                    
    catch (SocketException)
                    {
                        Close(user);
                    }
                    
    catch
                    {

                    }
                }
                
    else//如果接收到0字节的数据说明客户端关闭了Socket,那我们也要关闭Socket
                {
                    Close(user);
                }
              
            }
            
    /// <summary>
            
    /// 断开连接
            
    /// </summary>
            
    /// <param name="u"></param>
            void Close(User u)
            {
                Console.WriteLine(u.Userid 
    + "连接断开");
                
    return;
            }
            
    /// <summary>
            
    /// 收到信息的处理函数
            
    /// </summary>
            
    /// <param name="u"></param>
            
    /// <param name="msg"></param>
            void GetMsg(User u,byte[] msg)
            {
                
    string _msg=Encoding.UTF8.GetString(msg);
                Console.WriteLine(u.Userid 
    + "收到数据:" + _msg);
                SendMsg(u, msg);
            }
            
    /// <summary>
            
    /// 发送信息
            
    /// </summary>
            
    /// <param name="user"></param>
            
    /// <param name="msg"></param>
            void SendMsg(User user,byte[] msg)
            {
                
    try
                {
                    user.mysocket.BeginSend(msg, 
    0, msg.Length, SocketFlags.None, new AsyncCallback(Sendcallback), user);
                    
    string str=Encoding.UTF8.GetString(msg);
                    Console.WriteLine(user.Userid 
    + "发送数据:" + str);
                }
                
    catch (SocketException)
                {
                    Close(user);
                } 
            }
            
    /// <summary>
            
    /// 发送信息的回调
            
    /// </summary>
            
    /// <param name="ar"></param>
            void Sendcallback(IAsyncResult ar)
            {
               
     User u = (User)ar.AsyncState;
                
    try
                {
                    u.mysocket.EndSend(ar);
                }
                
    catch (System.Exception ex)
                {
                    
                }
            }
        }
    }

    客户端:

    代码
                client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                client.Connect(
    "127.0.0.1"8808);
                
    for(int i=1;i<51;i++)
                {
                    
    //发送信息
                    byte[] buffer = Encoding.UTF8.GetBytes("Login|"+i);
                    client.Send(buffer, 
    0, buffer.Length, SocketFlags.None);
                    
    //接受信息
                    byte[] buffer1=new byte[1024];
                    client.Receive(buffer1, 
    0, buffer1.Length, SocketFlags.None);
                    
    string str=Encoding.UTF8.GetString(buffer);
                    Console.WriteLine(
    "收到服务端返回信息:"+str);
                }
  • 相关阅读:
    BZOJ2303:[APIO2011]方格染色(并查集)
    BZOJ1116:[POI2008]CLO(并查集)
    BZOJ4011:[HNOI2015]落忆枫音(DP,拓扑排序)
    洛谷1387 最大正方形
    洛谷 P1858 多人背包
    vijos 1085 Sunnypig闯三角关
    vijos 1030 重叠的方框
    codevs 1001 舒适的路线 WK
    1266. [NOIP2012] 借教室
    codevs 2370 小机房的树
  • 原文地址:https://www.cnblogs.com/bobofsj11/p/1672874.html
Copyright © 2020-2023  润新知