0

仕事のために、プロトコルとして TCP を使用して最大 8000/10000 のアクティブな接続を処理できるサーバーを作成する必要があります。

以前に IOCP を使用したことがありますが、高負荷の後にサーバーがイベントを失い始めるという奇妙な状況が発生しています。

アーキテクチャをテストするために、受信したすべてのものを送信するだけのクライアントとサーバーを作成しました。これは最大 1000/2000 のクライアントで正常に動作しますが、より多くの接続を取得し始めると、IOCP コールバックが呼び出されません!

サーバーとクライアントがローカル マシンで実行されている

1 ミリ秒の送受信イベントの途中に Thread.Sleep を配置すると、すべて正常に動作しますが、サーバーが処理できるネットワーク スループットは大幅に低下します。私は Thread.Yield と Thread.Sleep(0) を試しました。これは Yieald に非常に似ていますが、有用な結果はありませんでした。

私の開発マシンは 8 GB の RAM を搭載した i7-3770 であるため、この負荷を処理できます。Thread.Sleep を使用すると、CPU 消費量は 30% 未満であり、イベントを失うことなく最大 10000 の接続を処理できますが、200mbps (クライアント + サーバー) のスループットで処理できます...システムがイベントを失わない場合、スレッドはありません。スリープ、サーバーは最大 8 Gbps のスループットを処理できます!

8192 のバッファ サイズを使用しています。

最良の状態で最適化するために、私のコードは必要なすべての読み取りバッファーを事前に初期化し、SocketAsyncEventArgs の読み取り/書き込みを行います (以下のコードでは初期化がありますが、以下のコードを拡張して必要なものをすべて事前に初期化するスーパー クラスがあります。

ここにサーバー部分のコードがあります

    public bool SendAsync(byte[] Buffer, int Offset, int Length)
    {
        // Verifica se è connesso
        if (this.IsConnected == false)
        {
            return false;
        }

        // Attende un eventuale invio in corso
        this.sendAsyncAutoResetEvent.WaitOne();

        if (this.sendSocketAsyncEventArgs == null)
        {
            // Inizializza l'oggetto contenente le informazioni per la gestione asincrona (IOCP)
            // dell'invio dei dati
            this.sendSocketAsyncEventArgs = new SocketAsyncEventArgs();
            this.sendSocketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(
                this.SocketAsyncCallback);
        }

        try
        {
            this.sendSocketAsyncEventArgs.SetBuffer(Buffer, Offset, Length);
        }
        catch (ObjectDisposedException)
        {
            this.sendAsyncAutoResetEvent.Set();
            return false;
        }
        catch (NullReferenceException)
        {
            this.sendAsyncAutoResetEvent.Set();
            return false;
        }

        return this.SendAsyncInternal();
    }

    private bool SendAsyncInternal()
    {
        try
        {
            // Prova ad avviare la ricezione asincrona
            if (this.socket.SendAsync(this.sendSocketAsyncEventArgs) == false)
            {
                // L'operazione si è completata in modo sincrono, gestisce gli eventi
                this.SocketAsyncCallback(this, this.sendSocketAsyncEventArgs);
            }
        }
        catch (SocketException e)
        {
            // Imposta l'eccezione
            this.lastSocketException = e;
            this.sendAsyncAutoResetEvent.Set();

            return false;
        }
        catch (ObjectDisposedException)
        {
            this.sendAsyncAutoResetEvent.Set();
            return false;
        }
        catch (NullReferenceException)
        {
            this.sendAsyncAutoResetEvent.Set();
            return false;
        }

        return true;
    }

    protected void SocketAsyncCallback(object sender, SocketAsyncEventArgs e)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(this.ProcessSocketEvent), e);
    }

    private void ProcessSocketEvent(object State)
    {
        SocketAsyncEventArgs e = State as SocketAsyncEventArgs;

        try
        {
            if
            (
                // Richiesta chiusura della connessione
                (
                    e.LastOperation != SocketAsyncOperation.Connect
                    &&
                    e.SocketError == SocketError.Success
                    &&
                    e.BytesTransferred == 0
                )
                ||
                e.SocketError == SocketError.OperationAborted
                ||
                e.SocketError == SocketError.ConnectionReset
            )
            {
                // Termina la connessione
                this.Close();
            }
            else if (e.SocketError == SocketError.ConnectionRefused)
            {
                this.ProcessSocketConnectRefused(e);
            }
            else
            {
                // Verifica la presenza di eventuali errori
                if (e.SocketError != SocketError.Success)
                {
                    throw new Exception(e.SocketError.ToString());
                }

                switch (e.LastOperation)
                {
                    case SocketAsyncOperation.Connect:

                        this.ProcessSocketConnect(e);
                        break;

                    case SocketAsyncOperation.Receive:

                        this.ProcessSocketReceive(e);
                        break;

                    case SocketAsyncOperation.Send:

                        this.ProcessSocketSend(e);
                        this.sendAsyncAutoResetEvent.Set();
                        break;

                    default:
                        break;
                }
            }
        }
        catch (ObjectDisposedException)
        {
            // do nothing
        }
        catch (NullReferenceException)
        {
            // do nothing
        }
    }

    private void ProcessSocketConnect(SocketAsyncEventArgs e)
    {
        this.OnConnectionEstablished();
    }

    private void ProcessSocketConnectRefused(SocketAsyncEventArgs e)
    {
        this.OnConnectionRefused();
    }

    private void ProcessSocketReceive(SocketAsyncEventArgs e)
    {
        this.lastPacketRecievedAt = DateTime.Now;
        this.OnDataReceived(e.Buffer, e.Offset, e.BytesTransferred);
    }

    private void ProcessSocketSend(SocketAsyncEventArgs e)
    {
        this.lastPacketSendedAt = DateTime.Now;
        this.OnDataSended(e.Buffer, e.Offset, e.BytesTransferred);
    }

ご協力いただきありがとうございます!

編集

オペレーティング システムが Windows 8 64Bit であることを指定するのを忘れていました

4

0 に答える 0