Изучаю пример от 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; }
}
Смортю здесь используют Stack, у меня вопрос, как работать с каждым сокетом отдельно? Как идентифицировать соединение и например отсоединить? Буду рад помощи
Цикл
public void sendToAll() {
foreach(SocketAsyncEventArgs eventargs in m_pool) {
AsyncUserToken token = eventargs.UserToken as AsyncUserToken;
token.Socket.Send(Encoding.ASCII.GetBytes("Test"));
}
}
Не работал с сокетами в C#, но там как и везде обязан быть некий идентификатор соединения, доступный из сохраняемого списка и при каждой обработке сообщения.
В приведённом коде на такой идентификатор смахивает поле UserToken объекта SocketAsyncEventArgs. Это значение можно легко получать (оно есть в аргументах всех методов работы с клиентами), и с его же помощью можно манипулировать соединением, отправлять сообщения.
MSDN говорит, что класс Socket имеет метод Close() для отключения соединения. Объект UserToken как раз имеет соответствующее поле Socket. И оно используется в методе CloseClientSocket, который, в свою очередь, и производит нужное Вам действие — отключает клиента, при этом, вежливо его уведомляя и удаляя соединение из списка SocketAsyncEventArgsPool.
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости