关于C#的Socket和SocketAsyncEventArgs问题???

ck863 2013-09-26 08:13:11
最近有个项目要用socket(tcp),在网上看了不少例子,还是不太清楚,主要是对SocketAsyncEventArgs这个类的机制不明白,请各位大侠指教…

能不能从客户端链接开始,说明一下SocketAsyncEventArgs这个类的工作机制,及关键的 方法属性,这个类和socket是怎么协同工作的???

哪位大侠能不能给深入的解释一下,不知道我说的是不是明白?????

...全文
934 17 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
如果你使用 silverlight,那么只能使用 SocketAsyncEventArgs。那个时候有一些意义。因为你没有别的更清晰的方式进行编程。 如果不是silverlight,可以先不用考虑它。 随便贴出一点silverlight里边的代码:
        public void InitTcpGateWay(string server, int port, string SeparatedText)
        {
            Separated = Encoding.UTF8.GetBytes(SeparatedText);
            _Server = server;
            _Port = port;
            var ConnectArgs = new SocketAsyncEventArgs { RemoteEndPoint = new DnsEndPoint(this.Server, this.Port) };
            ConnectArgs.Completed += ConnectArgs_Completed;
            clt = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clt.ConnectAsync(ConnectArgs);
        }

        private Socket clt;

        void ConnectArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.SocketError != SocketError.Success)
                throw new Exception("网络连接失败。请检查服务器或者网络。");

            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Connect:
                    e.SetBuffer(new byte[409600], 0, 409600);
                    clt.ReceiveAsync(e);
                    break;
                case SocketAsyncOperation.Receive:
                    ProcessReceive(e);
                    clt.ReceiveAsync(e);
                    break;
            }
        }


        private List<byte> ReadDatas = new List<byte>();

        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0)
            {
                var len = e.BytesTransferred;
                for (var i = 0; i < len; i++)
                    ReadDatas.Add(e.Buffer[i]);
                if (ReadDatas.Count > Separated.Length && EndWithSeparated(ReadDatas.ToArray()))
                {
                    ReadDatas.RemoveRange(ReadDatas.Count - Separated.Length, Separated.Length);
                    foreach (var line in Split(ReadDatas.ToArray()))  //分割为多个消息
                    {
                        var ln = DecompressedAndGetString(line);  //解密为字符串命令
                        new Thread(() => ProcessReceive(ln)).Start();  //执行客户端命令
                    }
                    ReadDatas.Clear();
                }
            }
        }
  • 打赏
  • 举报
回复
引用 7 楼 sj178220709 的回复:
iocp?这玩意确实很难懂,我大三时搞java web服务的时候,也是开始用一个请求一个线程,服务器根本受不了。 后来想用aio做,但那个通信模型实在是复杂,当时水平也不行,就不了了之了。
跟iocp没有什么关系。 .net framework的 TcpListener就是基于IOCP的。 而SocketAsyncEventArgs只不过是一个参数调用类型(就好像你可以使用ado.net也可以使用ef来调用sql server一样),这个参数形式跟服务系统用不用IOCP,没有关系。
Neusoft06 2013-10-07
  • 打赏
  • 举报
回复
4.0 没有更好的方法吗
华为黑名单 2013-10-06
  • 打赏
  • 举报
回复
UP 有什么用?
ck863 2013-09-30
  • 打赏
  • 举报
回复
引用 9 楼 kkkkkxiaofei 的回复:
[quote=引用 8 楼 ck863 的回复:] 怎么没有人回答呢?? 我再 up^^^
你都不说到底哪里不懂,让别人怎么回答,我最近刚好在做这块[/quote] SocketAsyncEventArgs 和 socket 如何配合工作的??机制是什么?
  • 打赏
  • 举报
回复
引用 8 楼 ck863 的回复:
怎么没有人回答呢?? 我再 up^^^
你都不说到底哪里不懂,让别人怎么回答,我最近刚好在做这块
ck863 2013-09-29
  • 打赏
  • 举报
回复
怎么没有人回答呢?? 我再 up^^^
  • 打赏
  • 举报
回复
iocp?这玩意确实很难懂,我大三时搞java web服务的时候,也是开始用一个请求一个线程,服务器根本受不了。 后来想用aio做,但那个通信模型实在是复杂,当时水平也不行,就不了了之了。
kchen863 2013-09-28
  • 打赏
  • 举报
回复
Up^^^^^^^^^^^^^^^^^^^^
ck863 2013-09-27
  • 打赏
  • 举报
回复
msdn上的例子

// Implements the connection logic for the socket server.  
// After accepting a connection, all data read from the client 
// is sent back to the client. The read and echo back to the client pattern 
// is continued until the client disconnects.
class Server
{
    private int m_numConnections;   // the maximum number of connections the sample is designed to handle simultaneously 
    private int m_receiveBufferSize;// buffer size to use for each socket I/O operation 
    BufferManager m_bufferManager;  // represents a large reusable set of buffers for all socket operations
    const int opsToPreAlloc = 2;    // read, write (don't alloc buffer space for accepts)
    Socket listenSocket;            // the socket used to listen for incoming connection requests
    // pool of reusable SocketAsyncEventArgs objects for write, read and accept socket operations
    SocketAsyncEventArgsPool m_readWritePool;
    int m_totalBytesRead;           // counter of the total # bytes received by the server
    int m_numConnectedSockets;      // the total number of clients connected to the server 
    Semaphore m_maxNumberAcceptedClients;

    // Create an uninitialized server instance.  
    // To start the server listening for connection requests
    // call the Init method followed by Start method 
    //
    // <param name="numConnections">the maximum number of connections the sample is designed to handle simultaneously</param>
    // <param name="receiveBufferSize">buffer size to use for each socket I/O operation</param>
    public Server(int numConnections, int receiveBufferSize)
    {
        m_totalBytesRead = 0;
        m_numConnectedSockets = 0;
        m_numConnections = numConnections;
        m_receiveBufferSize = receiveBufferSize;
        // allocate buffers such that the maximum number of sockets can have one outstanding read and 
        //write posted to the socket simultaneously  
        m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc,
            receiveBufferSize);

        m_readWritePool = new SocketAsyncEventArgsPool(numConnections);
        m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); 
    }

    // Initializes the server by preallocating reusable buffers and 
    // context objects.  These objects do not need to be preallocated 
    // or reused, but it is done this way to illustrate how the API can 
    // easily be used to create reusable objects to increase server performance.
    //
    public void Init()
    {
        // Allocates one large byte buffer which all I/O operations use a piece of.  This gaurds 
        // against memory fragmentation
        m_bufferManager.InitBuffer();

        // preallocate pool of SocketAsyncEventArgs objects
        SocketAsyncEventArgs readWriteEventArg;

        for (int i = 0; i < m_numConnections; i++)
        {
            //Pre-allocate a set of reusable SocketAsyncEventArgs
            readWriteEventArg = new SocketAsyncEventArgs();
            readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed);
            readWriteEventArg.UserToken = new AsyncUserToken();

            // assign a byte buffer from the buffer pool to the SocketAsyncEventArg object
            m_bufferManager.SetBuffer(readWriteEventArg);

            // add SocketAsyncEventArg to the pool
            m_readWritePool.Push(readWriteEventArg);
        }

    }

    // Starts the server such that it is listening for 
    // incoming connection requests.    
    //
    // <param name="localEndPoint">The endpoint which the server will listening 
    // for connection requests on</param>
    public void Start(IPEndPoint localEndPoint)
    {
        // create the socket which listens for incoming connections
        listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        listenSocket.Bind(localEndPoint);
        // start the server with a listen backlog of 100 connections
        listenSocket.Listen(100);

        // post accepts on the listening socket
        StartAccept(null);            

        //Console.WriteLine("{0} connected sockets with one outstanding receive posted to each....press any key", m_outstandingReadCount);
        Console.WriteLine("Press any key to terminate the server process....");
        Console.ReadKey();
    }


    // Begins an operation to accept a connection request from the client 
    //
    // <param name="acceptEventArg">The context object to use when issuing 
    // the accept operation on the server's listening socket</param>
    public void StartAccept(SocketAsyncEventArgs acceptEventArg)
    {
        if (acceptEventArg == null)
        {
            acceptEventArg = new SocketAsyncEventArgs();
            acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed);
        }
        else
        {
            // socket must be cleared since the context object is being reused
            acceptEventArg.AcceptSocket = null;
        }

        m_maxNumberAcceptedClients.WaitOne();
        bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg);
        if (!willRaiseEvent)
        {
            ProcessAccept(acceptEventArg);
        }
    }

    // This method is the callback method associated with Socket.AcceptAsync 
    // operations and is invoked when an accept operation is complete
    //
    void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e)
    {
        ProcessAccept(e);
    }

    private void ProcessAccept(SocketAsyncEventArgs e)
    {
        Interlocked.Increment(ref m_numConnectedSockets);
        Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
            m_numConnectedSockets);

        // Get the socket for the accepted client connection and put it into the 
        //ReadEventArg object user token
        SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop();
        ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket;

        // As soon as the client is connected, post a receive to the connection
        bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
        if(!willRaiseEvent){
            ProcessReceive(readEventArgs);
        }

        // Accept the next connection request
        StartAccept(e);
    }

    // This method is called whenever a receive or send operation is completed on a socket 
    //
    // <param name="e">SocketAsyncEventArg associated with the completed receive operation</param>
    void IO_Completed(object sender, SocketAsyncEventArgs e)
    {
        // determine which type of operation just completed and call the associated handler
        switch (e.LastOperation)
        {
            case SocketAsyncOperation.Receive:
                ProcessReceive(e);
                break;
            case SocketAsyncOperation.Send:
                ProcessSend(e);
                break;
            default:
                throw new ArgumentException("The last operation completed on the socket was not a receive or send");
        }       

    }

    // This method is invoked when an asynchronous receive operation completes. 
    // If the remote host closed the connection, then the socket is closed.  
    // If data was received then the data is echoed back to the client.
    //
    private void ProcessReceive(SocketAsyncEventArgs e)
    {
        // check if the remote host closed the connection
        AsyncUserToken token = (AsyncUserToken)e.UserToken;
        if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
        {
            //increment the count of the total bytes receive by the server
            Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
            Console.WriteLine("The server has read a total of {0} bytes", m_totalBytesRead);

            //echo the data received back to the client
            e.SetBuffer(e.Offset, e.BytesTransferred);
            bool willRaiseEvent = token.Socket.SendAsync(e);
            if (!willRaiseEvent)
            {
                ProcessSend(e);
            }

        }
        else
        {
            CloseClientSocket(e);
        }
    }

    // This method is invoked when an asynchronous send operation completes.  
    // The method issues another receive on the socket to read any additional 
    // data sent from the client
    //
    // <param name="e"></param>
    private void ProcessSend(SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            // done echoing data back to the client
            AsyncUserToken token = (AsyncUserToken)e.UserToken;
            // read the next block of data send from the client
            bool willRaiseEvent = token.Socket.ReceiveAsync(e);
            if (!willRaiseEvent)
            {
                ProcessReceive(e);
            }
        }
        else
        {
            CloseClientSocket(e);
        }
    }

    private void CloseClientSocket(SocketAsyncEventArgs e)
    {
        AsyncUserToken token = e.UserToken as AsyncUserToken;

        // close the socket associated with the client
        try
        {
            token.Socket.Shutdown(SocketShutdown.Send);
        }
        // throws if client process has already closed
        catch (Exception) { }
        token.Socket.Close();

        // decrement the counter keeping track of the total number of clients connected to the server
        Interlocked.Decrement(ref m_numConnectedSockets);
        m_maxNumberAcceptedClients.Release();
        Console.WriteLine("A client has been disconnected from the server. There are {0} clients connected to the server", m_numConnectedSockets);

        // Free the SocketAsyncEventArg so they can be reused by another client
        m_readWritePool.Push(e);
    }

}  
























ck863 2013-09-27
  • 打赏
  • 举报
回复
引用 2 楼 zanfeng 的回复:
SocketAsyncEventArgs是基于完成端口的。需要3.5框架。 msdn上有一个很好的例子。可以拿过来直接用。
例子我看了不少啊,就是不太明白啊,需要大侠指点迷津呀
ck863 2013-09-27
  • 打赏
  • 举报
回复
upup upup upup upup upup
足球中国 2013-09-26
  • 打赏
  • 举报
回复
SocketAsyncEventArgs是基于完成端口的。需要3.5框架。 msdn上有一个很好的例子。可以拿过来直接用。
  • 打赏
  • 举报
回复
这个类比较混乱,完全有道理不用它。 使用比较简洁的Accept、Receive(或者BeginAccept、BeginReceive)就行了。

111,089

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧