0

Win APIを呼び出して、C#でIOCPサーバーを作成しています。CPUコアに応じて、1つの受け入れスレッド接続とワーカースレッドがあります。

私の問題は、2 つのスレッドが同時に同じデータを処理しようとしているということです。次のスニペットに基づいて、解決策を教えてもらえますか、それともこれは設計上の問題ですか?

public class WorkerThread
    {
        public void Worker(NetSharedData data)
        {
            IntPtr bytestransfer = Marshal.AllocHGlobal(sizeof(UInt32));
            IntPtr clientid = Marshal.AllocHGlobal(sizeof(UInt32));
            IntPtr poverlapped = Marshal.AllocHGlobal(sizeof(UInt32));
            Console.WriteLine("Worker thread running");
            while (true)
            {
                Marshal.WriteInt32(clientid, 0);
                Marshal.WriteInt32(bytestransfer, 0);
                if (SocketInvoke.GetQueuedCompletionStatus(data.completionport, bytestransfer, clientid, poverlapped, SocketInvoke.INFINITE) == true)
                {
                        if (Marshal.ReadInt32(poverlapped) == 0)
                        {
                            //thread shutdown
                            Console.WriteLine("Worker thread shutdown");
                            break;
                        }
                        Client client = data.Clients[Marshal.ReadInt32(clientid)];
                        if (Marshal.ReadInt32(bytestransfer) != 0)
                        {
                            if (client.operationtype == SocketInvoke.FD_WRITE)
                            {
                                if (client.send_data.ispending_operation == true)
                                {
                                    client.SendLeft((uint)Marshal.ReadInt32(bytestransfer));
                                    break;
                                }
                            }
                            if (client.operationtype == SocketInvoke.FD_READ)
                            {
                                if (!client.Recv((uint)Marshal.ReadInt32(bytestransfer)))
                                {
                                    client.Close();
                                    break;
                                }
                                if (data.OnRecv(client) == true)
                                {
                                    //SendLeft test
                                }
                            }
                        }
                }
            }
        }
    }

/*
//THIS IS A CODE SNIPPET THAT BELONGS TO THE ACCEPT THREAD CLASS
*/

public virtual bool Recv(uint expected_data_transfer)
        {
            IntPtr pwsabuf;
            IntPtr wsaoverlapped;
            IntPtr bytes_recv = Marshal.AllocHGlobal(sizeof(int));
            IntPtr flags = Marshal.AllocHGlobal(sizeof(int));
            Marshal.WriteInt32(flags, 0);
            set_total_transfer(SocketInvoke.FD_READ, expected_data_transfer);
            pwsabuf = recv_data.rtn_wsabuffarray(recv_data.buffer, (uint)recv_data.bufflen);
            wsaoverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SocketInvoke.WSAOVERLAPPED)));
            Marshal.StructureToPtr(overlapped, wsaoverlapped, false);
            SocketInvoke.FillMemory(wsaoverlapped, (uint)Marshal.SizeOf(typeof(SocketInvoke.WSAOVERLAPPED)), 0);
            unsafe
            {
                setoptype(SocketInvoke.FD_READ);
                if (SocketInvoke.WSARecv(Convert.ToUInt32(sock.Handle.ToInt32()), pwsabuf,
                    (uint)1, bytes_recv, flags, wsaoverlapped, (IntPtr)null) == SocketInvoke.SOCKET_ERROR)
                {
                    if (Marshal.GetLastWin32Error() != SocketInvoke.WSA_IO_PENDING)
                    {
                        return false;
                    }
                    return true;
                }
            }
            return true;
        }

また、WSASend と WSARecv を使用して、データの部分的な送信または部分的な受信を取得することは可能ですか?

4

1 に答える 1

4

1) なぜこれをしているのですか? マネージ非同期ソケット メソッドを使用するか、ソケット コード全体を C または C++ で実行し、クリーンなインターフェイスを介してマネージ コードに公開します。

2)コードが不明確なので推測していますが...読み取りまたは書き込み操作ごとに一意のオーバーラップ構造が必要です。

3) はい、WSASend が失敗し、データの一部が送信される可能性があります。通常は、データ バッファーが OS ページ サイズよりも大きく、ロックされたページの制限に達した場合、または非ページ プールを使い果たした場合のみです。これが発生した場合、回復するためにできることは何もない可能性があります。処理できる接続の数に制限を設けて、そもそもそのような状況に陥らないようにしてください。100,000 の接続を処理できることを期待しますが、保留中の重複した操作の数に注意してください。

4) WSARecv は、すべての TCP 読み取り操作と同様に、1 バイトから提供されたバッファーのサイズの間の任意の値を返すことができます。0 が返された場合、ピアは接続の送信側をシャットダウンしています。

5) AcceptEx を使用して、その Accept スレッドを削除します。専用の Accept スレッドがあると、1 つのプログラム内から複数のポートでのリッスンをサポートしている場合、別のスレッドがコンテキスト スイッチに切り替えられ、スケーリングに失敗します。

于 2012-11-24T10:39:43.337 に答える