2

基本的にはソケット接続しました。これが私のWaitDataメソッドです。

    public void WaitForData()
    {
        State state = new State();
        state.Client = socket;
        //issue first receive
        state.Client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(ServerReadCallback), state);
    }

これは、ソケットがデータを待機しているときに呼び出されます(常にデータを待機させたい)。したがって、新しいメッセージの受信が開始されるたびに(.BeginReceiveが呼び出される)、メインスレッドがWaitForDataを再度呼び出して、メッセージを受け入れ続けるようにします。これはどのように行われますか?

(ところで、メッセージの実際の受信をブロックするため、ServerReadCallbackでWaitForDataを呼び出すことはできません)。

説明が乱雑な場合は申し訳ありません。説明するのはかなり難しいと思いました。

4

2 に答える 2

1

メッセージの処理が完了したら、ServerReadCallBack ルーチンで別の BeginReceive を発行します。

    State state = new State();
    state.Client = socket;
    //issue first receive
    state.Client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(ServerReadCallback), state);

ただし、メッセージが可変長の場合、バッファに読み取られたデータがメッセージの一部である可能性があることに注意してください。メッセージ全体。または、メッセージ全体と別のメッセージの一部/全体。したがって、 ServerReadCallback はこれに対処できる必要があります-次のようなものです:

    private void OnDataReceived(IAsyncResult asyn)
    {
        ReceiveState rState = (ReceiveState)asyn.AsyncState;
        Socket client = rState.Client;
        SocketError socketError = SocketError.TypeNotFound;

        if (!client.Connected)
        {
            // Not Connected anymore ?
            return;
        }

        _LastComms = DateTime.Now;
        _LastIn = _LastComms;

        int dataOffset = 0; 
        int restOfData = 0;
        int dataRead = 0;
        Boolean StreamClosed = false;
        long rStateDataLength = 0;
        long LastrStateDataLength = 0;

        try
        {

            dataRead = client.EndReceive(asyn, out socketError);
        }
        catch (Exception excpt)
        {
           // Your code goes here..
        }

        if (socketError != SocketError.Success)
        {
            // Has Connection been lost ?
            OnConnectionDropped(client);
            return;
        }

        if (dataRead <= 0)
        {
            // Has connection been lost ?
            OnConnectionDropped(client);
            return;
        }

        while (dataRead > 0)
        {
            //check to determine what income data contain: size prefix or message
            if (!rState.DataSizeReceived)
            {
                //there is already some data in the buffer
                if (rState.Data.Length > 0)
                {
                    restOfData = PrefixSize - (int)rState.Data.Length;
                    rState.Data.Write(rState.Buffer, dataOffset, restOfData);
                    dataRead -= restOfData;
                    dataOffset += restOfData;
                }
                else if (dataRead >= PrefixSize)
                {  //store whole data size prefix
                    rState.Data.Write(rState.Buffer, dataOffset, PrefixSize);
                    dataRead -= PrefixSize;
                    dataOffset += PrefixSize;
                }
                else
                {  // store only part of the size prefix
                    rState.Data.Write(rState.Buffer, dataOffset, dataRead);
                    dataOffset += dataRead;
                    dataRead = 0;
                }

                if (rState.Data.Length == PrefixSize)
                {  //we received data size prefix 
                    rState.DataSize = BitConverter.ToInt32(rState.Data.GetBuffer(), 0);
                    rState.DataSizeReceived = true;
                    //reset internal data stream             
                    rState.Data.Position = 0;
                    rState.Data.SetLength(0);
                }
                else
                {  //we received just part of the prefix information 
                    //issue another read
                    client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
                       SocketFlags.None, new AsyncCallback(socketReadCallBack),
                          rState);
                    return;
                }
            }



            //at this point we know the size of the pending data

            // Object disposed exception may raise here
            try
            {
                rStateDataLength = rState.Data.Length;
                LastrStateDataLength = rStateDataLength;
            }
            catch (ObjectDisposedException Ode)
            {
                StreamClosed = true;
            }
            if (!StreamClosed)
            {

                if ((rStateDataLength + dataRead) >= rState.DataSize)
                {   //we have all the data for this message

                    restOfData = rState.DataSize - (int)rState.Data.Length;

                    rState.Data.Write(rState.Buffer, dataOffset, restOfData);
                    //Console.WriteLine("Data message received. Size: {0}",
                    //   rState.DataSize);

                    // Is this a heartbeat message ?
                    // This is my own thing - you may not need this..
                    if (rState.Data.Length == 2)
                    {
                        // Yes
                        HeartBeatReceived();
                    }
                    else

                    {
                       // Handle the received messsage

                        DecodeMessageReceived(GetStringFromStream(rState.Data));
                    }

                    dataOffset += restOfData;
                    dataRead -= restOfData;

                    //message received - cleanup internal memory stream
                    rState.Data = new MemoryStream();
                    rState.Data.Position = 0;
                    rState.DataSizeReceived = false;
                    rState.DataSize = 0;

                    if (dataRead == 0)
                    {  
                        //no more data remaining to process - issue another receive
                        if (_IsConnected)
                        {
                            client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
                               SocketFlags.None, new AsyncCallback(socketReadCallBack),
                                  rState);
                            return;
                        }
                    }
                    else
                        continue; //there's still some data to process in the buffers
                }
                else
                {  //there is still data pending, store what we've 
                    //received and issue another BeginReceive
                    if (_IsConnected)
                    {
                        rState.Data.Write(rState.Buffer, dataOffset, dataRead);

                        client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
                           SocketFlags.None, new AsyncCallback(socketReadCallBack), rState);

                        dataRead = 0;
                    }
                }
            }
            else
            {
                // Stream closed, but have we read everything ?
                if (LastrStateDataLength + dataRead == rState.DataSize)
                {
                    // We're equal, get ready for more
                    //no more data remaining to process - issue another receive
                    if (_IsConnected)
                    {
                        client.BeginReceive(rState.Buffer, 0, rState.Buffer.Length,
                           SocketFlags.None, new AsyncCallback(socketReadCallBack),
                              rState);
                    }
                    return;
                }
                else
                {
                    // We should have more..
                    // report error ?
                }
            }

            // If we've been disconnected, provide a graceful exit
            if (!_IsConnected)
                dataRead = -1;

        }
     }

このコードでは、私の rstate は次のとおりです。

public class ReceiveState
{
    public byte[] Buffer = new byte[1024]; //buffer for network i/o
    public int DataSize = 0; //data size to be received by the server
    public bool DataSizeReceived = false; //whether prefix was received
    public MemoryStream Data = new MemoryStream(); //place where data is stored
    public Socket Client;   //client socket
}
于 2012-12-04T22:53:38.747 に答える
0

あなたはこのようなことをしたい:

private ManualResetEvent _connectionAccepted;

public void WaitForData()
{
    while (true)
    {
        _connectionAccepted.Reset();

        socket.BeginAccept(new AsyncCallback(AcceptCallback), state);

        _connectionAccepted.WaitOne();
    }
}

private void Acceptcallback(IAsyncResult ar)
{
     _connectionAccepted.Set();

     Socket socket = (Socket)ar.AsyncState;
     Socket handler = socket.EndAccept(ar);

     State state = new State();
     state.Client = handler;

     handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, new AsyncCallback(ServerReadCallback), handler);
}

したがって、基本的に、無限にループしています。接続を取得すると、それを受け入れ始めます。接続の受け入れを処理するコードにいるときは、続行できることをメインループに通知します。次に、EndAccept を実行すると、2 番目のソケットが提供されます。そのソケットはクライアントとの通信に使用されるため、最初のソケットは引き続き新しい接続を受け入れることができます。

WaitForData() への 1 回の呼び出しだけが必要です。これがループの場所です。そのため、名前付けなどのレベルを上げることができます。しかし、これは一般的な考え方です。

于 2012-12-04T19:40:05.933 に答える