Блокировка гнезда через потоки - PullRequest
2 голосов
/ 30 мая 2011

Это хорошая идея в моем ReceiveCallBack асинхронного сокета для блокировки () сокета там? Я спрашиваю, потому что возможно, что другой поток одновременно отправляет данные в сокет.

private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;

lock(client)
{
    int bytesRead = client.EndReceive(ar);
    // do some work

    // Kick off socket to receive async again.
    client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReceiveCallback), state);
}
}    

// This is commonly called by another thread
public void SendMessage(string cmdName, Object data)
{
    lock (client)
    {
         client.Send(arrayofdata, 0, arraylength, 0);
    }
}

Ответы [ 2 ]

4 голосов
/ 30 мая 2011

Если вы хотите сделать его потокобезопасным и иметь возможность отправлять и получать одновременно, вам нужно создать два объекта блокировки синхронизации:

private readonly object sendSyncRoot = new object();
private readonly object receiveSyncRoot = new object();

private void ReceiveCallback(IAsyncResult ar)
{
    StateObject state = (StateObject)ar.AsyncState;
    Socket client = state.workSocket;

    lock (receiveSyncRoot)
    {
        int bytesRead = client.EndReceive(ar);
        // do some work

        // Kick off socket to receive async again.
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
    }
}

// This is commonly called by another thread
public void SendMessage(string cmdName, Object data)
{
    lock (sendSyncRoot)
        client.Send(arrayofdata, 0, arraylength, 0);
}

Как правило, рекомендуется выделять syncRoot объекты вместо блокировки других классов или членов. Это позволяет избежать тонких тупиков.

3 голосов
/ 31 мая 2011

Нет.Не делай этого.Лучший способ обработать сокет - это инкапсуляция.Не подвергайте это ничему, кроме того, чтобы это объявил класс.Таким образом, легко убедиться, что одновременно ожидается только одно получение.Нет необходимости использовать замок для этого.

Что касается отправки.сделать что-то вроде этого:

public class MyClient
{
    private readonly Queue<byte[]> _sendBuffers = new Queue<byte[]>();
    private bool _sending;
    private Socket _socket;

    public void Send(string cmdName, object data)
    {
        lock (_sendBuffers)
        {
            _sendBuffers.Enqueue(serializedCommand);
            if (_sending) 
                return;

            _sending = true;
            ThreadPool.QueueUserWorkItem(SendFirstBuffer);
        }
    }

    private void SendFirstBuffer(object state)
    {
        while (true)
        {
            byte[] buffer;
            lock (_sendBuffers)
            {
                if (_sendBuffers.Count == 0)
                {
                    _sending = false;
                    return;
                }

                buffer = _sendBuffers.Dequeue();
            }

            _socket.Send(buffer);
        }
    }
}

Этот подход не блокирует ни одного из вызывающих абонентов, и все запросы на отправку обрабатываются по очереди.

...