2

したがって、私のソフトウェアでは、ネットワーク上でディスカバー ブロードキャストを送信すると、そのブロードキャストを受信するすべての「クライアント」が TCP 経由で接続されます。私が持っているものでは、「OK」に機能しているように見えますが、もっと良い方法が必要だと感じています. 私が見ているのは、現在別のソケットの受け入れに取り組んでいるため、ソフトウェアへの一部の TCP 接続が拒否されていることです (と思います)。したがって、現在のバージョンでは、約 80% の確率でソケットを受け入れることができます。それ以上の場合もありますが、通常は 80% 前後です。残りは私のソフトウェアによって拒否され、その理由はわかりません。私にはそれは受け入れられませんが、この数値を改善することはできません。

これは、TCP クライアントを受け入れ、接続された新しいソケットについて他のクラスに通知するために使用するクラスです。

public class AsynchronousSocketListener
{
    // Thread signal.
    public ManualResetEvent allDone = new ManualResetEvent(false);
    public event EventHandler<ErtdRawDataArgs> ClientConnected;

    private string bindingIp;
    public string AddressBind 
    {
        get { return this.bindingIp; } 
        private set { this.bindingIp = value; } 
    }

    private int port;
    public int Port
    {
        get { return this.port; }
        private set { this.port = value; }
    }

    private Socket listener;

    public AsynchronousSocketListener(string bindingIp, int port) 
    {
        this.bindingIp = bindingIp;
        this.port = port;
    }

    protected void OnClientConnected(string data, IPEndPoint clientEP)
    {
        if (this.ClientConnected == null)
            return;

        Task.Factory.StartNew(() =>
        {
            //build args
            ErtdRawDataArgs args = new ErtdRawDataArgs(Encoding.Default.GetBytes(data));
            args.Source = string.Format("{0}:{1}", clientEP.Address.ToString(), clientEP.Port);
            this.ClientConnected(this, args);
        });
    }

    public void Close()
    {
        if (this.listener == null || !this.listener.Connected)
            return;

        this.listener.Shutdown(SocketShutdown.Both);
        this.listener.Close();
    }

    public void StartListening() 
    {
        Task.Factory.StartNew(() =>
        {
            // Data buffer for incoming data.
            byte[] bytes = new Byte[1024];

            // Establish the local endpoint for the socket.
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(this.bindingIp), this.port);

            // Create a TCP/IP socket.
            listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Bind the socket to the local endpoint and listen for incoming connections.
            try
            {
                listener.Bind(localEndPoint);
                int maxConnections = (int)SocketOptionName.MaxConnections;
                listener.Listen(maxConnections);

                while (true)
                {
                    // Set the event to nonsignaled state.
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections.
                    listener.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        listener);

                    // Wait until a connection is made before continuing.
                    allDone.WaitOne();
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        });
    }

    public void AcceptCallback(IAsyncResult ar) 
    {
        // Signal the main thread to continue.
        allDone.Set();

        // Get the socket that handles the client request.
        Socket listener = (Socket) ar.AsyncState;
        Socket handler = listener.EndAccept(ar);

        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = handler;
        handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(ReadCallback), state);
    }

    public void ReadCallback(IAsyncResult ar) 
    {
        String content = String.Empty;

        // Retrieve the state object and the handler socket
        // from the asynchronous state object.
        StateObject state = (StateObject) ar.AsyncState;
        Socket handler = state.workSocket;

        // Read data from the client socket. 
        int bytesRead = handler.EndReceive(ar);

        if (bytesRead > 0) {
            // There  might be more data, so store the data received so far.
            state.sb.Append(Encoding.ASCII.GetString(
                state.buffer,0,bytesRead));

            // Check for end-of-file tag. If it is not there, read 
            // more data.
            content = state.sb.ToString();
            OnClientConnected(content, handler.RemoteEndPoint as IPEndPoint);

            //close socket
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();
        }
    }
}

このコードを改善する方法はありますか、またはほぼ同時に TCP 接続を受け入れる結果を改善するために、まったく異なるものがありますか?

4

1 に答える 1

1

さて、接続を受け入れてから接続が「確立」されてから、別の接続を受け入れることができるようになるまでの期間があります。待機ハンドルなどを使用すると、おそらくかなり遅くなります。

コードを読み直した後、概念的に別の接続を受け入れることができるポイントは、 を呼び出したときですEndAccept。呼び出す前にイベントを設定しているようです。これは、前に呼び出すことができ、前の呼び出しが呼び出される前に別の接続を受け入れることができることEndAcceptを意味します。それが問題かどうかはわかりませんが、私が知る限り、それは合法です。ただし、コードを単純化してイベントを回避し、現在の受け入れ中に次の BeginAccept をチェーンして、次の前に呼び出されるようにすることができます。BeginAcceptEndAcceptEndAcceptEndAcceptBeginAccept

私がしているのは、現在の受け入れ内から次の受け入れを連鎖させることです。 例えば:

listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Any, 62000));
listener.Listen(1000);
listener.BeginAccept(OnAccept, listener);

private void OnAccept(IAsyncResult ar)
{
    Socket listener = (Socket)ar.AsyncState;
    Socket socket = listener.EndAccept(ar);
    listener.BeginAccept(OnAccept, listener);
    socket.BeginReceive(new byte[10], 0, 10, 0, (arReceive) => socket.EndReceive(arReceive), null);
}

もちろん、BeginAcceptSocketここで使用しています。しかし、コンセプトは同じBeginAcceptです...

これにより、新しい を開始する必要がなくなり、クロスプロセスTaskであるため約 50 倍遅い待機ハンドルを作成する必要がなくなりますlock

于 2012-09-05T19:08:01.847 に答える