Использование дизайна сервера SocketAsyncEventArgs

Используйте жабу, чтобы загрузить его, и вы можете просмотреть ссылки на диаграмме. также убедитесь, что у вас нет кода приложения, передающего sql из внешнего интерфейса, падение таблицы может привести к разрыву приложения.

Ссылка для скачивания http://www.toadsoft.com/toadmysql/FreewareDownload.htm

Если вы используете innoDB, попробуйте этот файл. 111] http://dev.mysql.com/doc/refman/5.1/en/show-table-status.html

7
задан davidfowl 15 July 2012 в 04:12
поделиться

1 ответ

Для эффективной реализации асинхронных сокетов каждому сокету потребуется более 1 SocketAsyncEventArgs. Также существует проблема с буфером byte [] в каждом SocketAsyncEventArgs. Короче говоря, байтовые буферы будут закреплены всякий раз, когда происходит управляемый переход в собственный режим (отправка / получение). Если вы выделяете SocketAsyncEventArgs и байтовые буферы по мере необходимости, вы можете столкнуться с OutOfMemoryExceptions со многими клиентами из-за фрагментации и неспособности GC сжать закрепленную память.

Лучший способ справиться с этим - создать класс SocketBufferPool, который будет выделять большое количество байтов и SocketAsyncEventArgs при первом запуске приложения, таким образом закрепленная память будет непрерывной. Затем просто повторно используйте буферы из пула по мере необходимости.

На практике я ' Мы сочли лучшим создать класс-оболочку вокруг SocketAsyncEventArgs и класса SocketBufferPool для управления распределением ресурсов.

В качестве примера приведем код для метода BeginReceive:

private void BeginReceive(Socket socket)
    {
        Contract.Requires(socket != null, "socket");

        SocketEventArgs e = SocketBufferPool.Instance.Alloc();
        e.Socket = socket;
        e.Completed += new EventHandler<SocketEventArgs>(this.HandleIOCompleted);

        if (!socket.ReceiveAsync(e.AsyncEventArgs)) {
            this.HandleIOCompleted(null, e);
        }
    }

А вот метод HandleIOCompleted:

private void HandleIOCompleted(object sender, SocketEventArgs e)
    {
        e.Completed -= this.HandleIOCompleted;
        bool closed = false;

        lock (this.sequenceLock) {
            e.SequenceNumber = this.sequenceNumber++;
        }

        switch (e.LastOperation) {
            case SocketAsyncOperation.Send:
            case SocketAsyncOperation.SendPackets:
            case SocketAsyncOperation.SendTo:
                if (e.SocketError == SocketError.Success) {
                    this.OnDataSent(e);
                }
                break;
            case SocketAsyncOperation.Receive:
            case SocketAsyncOperation.ReceiveFrom:
            case SocketAsyncOperation.ReceiveMessageFrom:
                if ((e.BytesTransferred > 0) && (e.SocketError == SocketError.Success)) {
                    this.BeginReceive(e.Socket);
                    if (this.ReceiveTimeout > 0) {
                        this.SetReceiveTimeout(e.Socket);
                    }
                } else {
                    closed = true;
                }

                if (e.SocketError == SocketError.Success) {
                    this.OnDataReceived(e);
                }
                break;
            case SocketAsyncOperation.Disconnect:
                closed = true;
                break;
            case SocketAsyncOperation.Accept:
            case SocketAsyncOperation.Connect:
            case SocketAsyncOperation.None:
                break;
        }

        if (closed) {
            this.HandleSocketClosed(e.Socket);
        }

        SocketBufferPool.Instance.Free(e);
    }

Приведенный выше код содержится в классе TcpSocket, который будет вызывать события DataReceived и DataSent. Следует обратить внимание на случай SocketAsyncOperation.ReceiveMessageFrom: block; если у сокета не было ошибки, он немедленно запускает другой BeginReceive (), который выделяет другой SocketEventArgs из пула.

Еще одно важное замечание - свойство SocketEventArgs SequenceNumber, установленное в методе HandleIOComplete. Хотя асинхронные запросы будут выполняться в порядке очереди, вы по-прежнему подвержены другим условиям гонки потоков. Поскольку код вызывает BeginReceive перед вызовом события DataReceived, существует вероятность того, что поток, обслуживающий исходный IOCP, заблокируется после вызова BeginReceive, но до запуска события, в то время как второе асинхронное получение завершается в новом потоке, который сначала вызывает событие DataReceived. Хотя это довольно редкий пограничный случай, это может произойти, и свойство SequenceNumber дает приложению-потребителю возможность гарантировать, что данные обрабатываются в правильном порядке.

Еще одна область, о которой следует помнить, - это асинхронные отправки. Часто запросы на асинхронную отправку выполняются синхронно (SendAsync возвращает false, если вызов завершился синхронно) и может серьезно снизить производительность. Дополнительные накладные расходы на асинхронный вызов, возвращающийся по IOCP, на практике могут привести к худшей производительности, чем просто использование синхронного вызова. Билл

10
ответ дан 7 December 2019 в 01:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: