I study an example from MSDN:

Server

class Server { private int m_numConnections; private int m_receiveBufferSize; BufferManager m_bufferManager; const int opsToPreAlloc = 2; Socket listenSocket; SocketAsyncEventArgsPool m_readWritePool; int m_totalBytesRead; int m_numConnectedSockets; Semaphore m_maxNumberAcceptedClients; public Server(int numConnections, int receiveBufferSize) { m_totalBytesRead = 0; m_numConnectedSockets = 0; m_numConnections = numConnections; m_receiveBufferSize = receiveBufferSize; m_bufferManager = new BufferManager(receiveBufferSize * numConnections * opsToPreAlloc, receiveBufferSize); m_readWritePool = new SocketAsyncEventArgsPool(numConnections); m_maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); } public void Init() { m_bufferManager.InitBuffer(); SocketAsyncEventArgs readWriteEventArg; for (int i = 0; i < m_numConnections; i++) { readWriteEventArg = new SocketAsyncEventArgs(); readWriteEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(IO_Completed); readWriteEventArg.UserToken = new AsyncUserToken(); m_bufferManager.SetBuffer(readWriteEventArg); m_readWritePool.Push(readWriteEventArg); } } public void Start(IPEndPoint localEndPoint) { listenSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); listenSocket.Bind(localEndPoint); listenSocket.Listen(100); StartAccept(null); } public void StartAccept(SocketAsyncEventArgs acceptEventArg) { if (acceptEventArg == null) { acceptEventArg = new SocketAsyncEventArgs(); acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(AcceptEventArg_Completed); } else { acceptEventArg.AcceptSocket = null; } m_maxNumberAcceptedClients.WaitOne(); bool willRaiseEvent = listenSocket.AcceptAsync(acceptEventArg); if (!willRaiseEvent) { ProcessAccept(acceptEventArg); } } void AcceptEventArg_Completed(object sender, SocketAsyncEventArgs e) { ProcessAccept(e); } private void ProcessAccept(SocketAsyncEventArgs e) { Interlocked.Increment(ref m_numConnectedSockets); SocketAsyncEventArgs readEventArgs = m_readWritePool.Pop(); ((AsyncUserToken)readEventArgs.UserToken).Socket = e.AcceptSocket; bool willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs); if (!willRaiseEvent) { ProcessReceive(readEventArgs); } StartAccept(e); } void IO_Completed(object sender, SocketAsyncEventArgs e) { 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"); } } private void ProcessReceive(SocketAsyncEventArgs e) { AsyncUserToken token = (AsyncUserToken)e.UserToken; if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred); e.SetBuffer(e.Offset, e.BytesTransferred); bool willRaiseEvent = token.Socket.SendAsync(e); if (!willRaiseEvent) { ProcessSend(e); } } else { CloseClientSocket(e); } } private void ProcessSend(SocketAsyncEventArgs e) { if (e.SocketError == SocketError.Success) { AsyncUserToken token = (AsyncUserToken)e.UserToken; bool willRaiseEvent = token.Socket.ReceiveAsync(e); if (!willRaiseEvent) { ProcessReceive(e); } } else { CloseClientSocket(e); } } private void CloseClientSocket(SocketAsyncEventArgs e) { AsyncUserToken token = e.UserToken as AsyncUserToken; try { token.Socket.Shutdown(SocketShutdown.Send); } catch (Exception) { } token.Socket.Close(); Interlocked.Decrement(ref m_numConnectedSockets); m_maxNumberAcceptedClients.Release(); m_readWritePool.Push(e); } } 

SocketAsyncEventArgsPool

 class SocketAsyncEventArgsPool { Stack<SocketAsyncEventArgs> m_pool; public SocketAsyncEventArgsPool(int capacity) { m_pool = new Stack<SocketAsyncEventArgs>(capacity); } public void Push(SocketAsyncEventArgs item) { if (item == null) { throw new ArgumentNullException("Items added to a SocketAsyncEventArgsPool cannot be null"); } lock (m_pool) { m_pool.Push(item); } } public SocketAsyncEventArgs Pop() { lock (m_pool) { return m_pool.Pop(); } } public int Count { get { return m_pool.Count; } } } 

BufferManager

 class BufferManager { int m_numBytes; byte[] m_buffer; Stack<int> m_freeIndexPool; int m_currentIndex; int m_bufferSize; public BufferManager(int totalBytes, int bufferSize) { m_numBytes = totalBytes; m_currentIndex = 0; m_bufferSize = bufferSize; m_freeIndexPool = new Stack<int>(); } public void InitBuffer() { m_buffer = new byte[m_numBytes]; } public bool SetBuffer(SocketAsyncEventArgs args) { if (m_freeIndexPool.Count > 0) { args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize); } else { if ((m_numBytes - m_bufferSize) < m_currentIndex) { return false; } args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize); m_currentIndex += m_bufferSize; } return true; } public void FreeBuffer(SocketAsyncEventArgs args) { m_freeIndexPool.Push(args.Offset); args.SetBuffer(null, 0, 0); } } internal class AsyncUserToken { public System.Net.Sockets.Socket Socket { get; set; } } 

Sortu here use Stack, I have a question, how to work with each socket separately? How to identify the connection and for example to disconnect? I will be glad to help

Cycle

 public void sendToAll() { foreach(SocketAsyncEventArgs eventargs in m_pool) { AsyncUserToken token = eventargs.UserToken as AsyncUserToken; token.Socket.Send(Encoding.ASCII.GetBytes("Test")); } } 

    1 answer 1

    I did not work with sockets in C #, but there, like everywhere else, there must be some connection identifier accessible from the saved list and every time the message is processed.

    In the following code, the SocketAsyncEventArgs object's UserToken field looks like this identifier. This value can be easily obtained (it is in the arguments of all methods of working with clients), and with its help you can manipulate the connection, send messages.

    MSDN says that the Socket class has a Close() method to disconnect. The UserToken object just has a corresponding Socket field. And it is used in the CloseClientSocket method, which, in turn, produces the action you need - it disables the client, while politely notifying it and removing the connection from the SocketAsyncEventArgsPool list.

    • But how for example to get all the clients and send a message to everyone? - Mike Waters
    • I did a foreach loop on m_pool but there was no reaction - Mike Waters
    • The SocketAsyncEventArgsPool object stores all connections in m_pool , passing through it you can perform the required actions. - AivanF.
    • @MikeWaters and what was in your cycle? - AivanF.
    • added in question, token.Socket catches System.NullReferenceException - Mike Waters