0

私はここでかなりの問題を抱えています。外部デバイスと通信するための実装を処理するモデルがある MVP アプリケーションがあります。アプリケーションで、このクラスの 4 つのインスタンスを作成します。各インスタンスは、一意の IP とポートを使用して UDP ソケット経由で外部デバイスと通信します。

すべての初期テストでは、4 つのビューがあり、各ビューには一意の各デバイスのカウントが表示されるため、すべて問題ないように見えました。テストのために、私は常に 1 つのデバイスにのみ接続し、他の 3 つの接続は何もしていませんでしたが、期待どおり、ビューには常にゼロのカウントが表示されました。

タイマーの起動に基づいて各インスタンスからのカウントをログに記録するために、個々の log4net ロガーをプログラムで作成し始めたときに問題が発生しました。私が見つけたのは、各ログ ファイルが同じカウントを記録しているということでした。これは自分の log4net 実装だと思っていましたが、残念なことに、デバッグ中にデバッガーで各インスタンスが同じカウントを返すのを見ました。

モデルのインスタンスが作成されると、それらはすべて、それぞれへの参照を保持するプレゼンターに渡されます。各モデルには一意の文字列識別子が与えられます。これは、デバッグ時にどのインスタンスを表示しているかを知る方法です (IP とポートは別として)。

また、カウントは、3 つのインスタンスに着信しない非請求 UDP パケットの受信時に設定されることに注意してください。

私の本能は以下の通りです。

HeadModel
-HeadModelAbstract
--SubModel
---SubModelAbstract

参照されるカウントはサブモデルにあります。機能が制限されたレベルの基本レベルのデバイスと通信するためのクラスが必要なため、このようにしました。ただし、より高度なデバイスには、その機能に加えて追加機能があります。私はもともとインターフェイスを渡したかったのですが、それを行うと、まだ公開したいサブモデルのプロパティとメソッドが隠されることがわかったので、ご覧のように抽象的な実装を使用しました。

ここまで頑張って助けてくれたすべての人に感謝します。

概要 - クラスの 4 つの一意のインスタンスがすべて同じ非静的プロパティに対して同じ値を返すのはなぜですか?

更新:ここにミスコードがあります

SystemStatus は、すべてのカウントと状態を保持します。ParseSystemStatus 関数は、UDP メッセージを受信するたびにトリガーされるイベント ハンドラーから呼び出されます。

public class SuccintClass : SuccintAbstract{

    UdpServer udpServer = null;

    public SuccintClass(int port){
        udpServer = new UdpServer(port); //Start receiver on port 3000
        udpServer.PacketReceived += client_UnsolicitedMessageReceived;
    }

    private void client_UnsolicitedMessageReceived(object sender, PacketReceivedEventArgs e) {



        ushort msgID = (ushort)((e.Buffer.Data[10]<<8) + e.Buffer.Data[11]);

        byte[] data = new byte[e.Buffer.Length];
        Array.Copy(e.Buffer.Data, 0, data, 0, e.Buffer.Length);

        switch (msgID) {
            case 9001:  
                break;
            case 0x5000:    
                break;
            case 9005:  //System Status
                ParseSystemStatus(data);
                OnSystemStatusReceived(new SystemStatusReceivedEventArgs(this.sysStatus));
                break;
            case 9014:  
                break;
            default:
                break;
        }
    }
    private SystemStatus sysStatus = SystemStatus.NullStatus;

    public void ParseSystemStatus(byte[] buffer) {
        int CounterOffset = 14;
        int[] converted = new int[6];

        for (int i = 0; i < 6; i++) {
            converted[i] = BitConverter.ToInt32(buffer, i * 4 + CounterOffset);
        }

        this.sysStatus.State = (SystemStatus.SystemState)converted[0];
        this.sysStatus.Count1 = converted[1];
        this.sysStatus.Count2= converted[2];
        this.sysStatus.Count3= converted[3];
        this.sysStatus.Count4= converted[4];
        this.sysStatus.Count5= converted[5];
    }
}

次に、UdpServerは次のようになります

sealed class UdpServer : IDisposable {
    public UdpServer( int serverPort ) {
        this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
        this.socket.Bind( new IPEndPoint( IPAddress.Any, serverPort ) );

        for ( int i = 0; i < 200; i++ ) {
            BeginAsyncReceive( );
        }
    }

    ~UdpServer( ) {
        Dispose( false );
    }

    public void Dispose( ) {
        Dispose( true );
        GC.SuppressFinalize( this );
    }

    private void Dispose( bool isDisposing ) {
        if ( !disposed ) {
            disposed = true;
            rwLock.AcquireWriterLock( Timeout.Infinite );
            socket.Close( );
            rwLock.ReleaseWriterLock( );

            while ( threads > 0 )
                Thread.Sleep( 1 );
        }
    }

    private bool disposed;

    private void BeginAsyncReceive( ) {
        rwLock.AcquireReaderLock( Timeout.Infinite );

        UdpPacketBuffer buffer = UdpPacketBufferPool.GetInstance( ).GetFromPool( );

        try {
            socket.BeginReceiveFrom( buffer.Data, 0, buffer.Data.Length, SocketFlags.None, ref buffer.RemoteEndPoint, EndAsyncReceive, buffer );
            Interlocked.Increment( ref threads );
        }
        catch ( SocketException exc ) {
            if ( logger.IsWarnEnabled ) {
                logger.Warn( "Error happened at the start of packet acquisition." );
                logger.Warn( exc.ToString( ) );
            }
        }
        catch ( ObjectDisposedException exc ) {
        }

        rwLock.ReleaseReaderLock( );
    }

    private void EndAsyncReceive( IAsyncResult asyncResult ) {
        BeginAsyncReceive( );

        rwLock.AcquireReaderLock( Timeout.Infinite );

        UdpPacketBuffer buffer = (UdpPacketBuffer)asyncResult.AsyncState;

        try {
            buffer.Length = socket.EndReceiveFrom( asyncResult, ref buffer.RemoteEndPoint );

            OnPacketReceived( new PacketReceivedEventArgs( buffer ) );
        }
        catch ( SocketException exc ) {
            logger.Warn( "Error happened during completion of packet acquisition." );
            logger.Warn( exc.Message );
            logger.Warn( exc.StackTrace );
        }
        catch ( ObjectDisposedException ) {
        }

        Interlocked.Decrement( ref threads );

        rwLock.ReleaseReaderLock( );
    }

    private void OnPacketReceived( PacketReceivedEventArgs args ) {
        EventHandler<PacketReceivedEventArgs> handler = PacketReceived;

        if ( handler != null ) {
            handler( this, args );
        }
    }

    public event EventHandler<PacketReceivedEventArgs> PacketReceived;

    private int threads;
    private ReaderWriterLock rwLock = new ReaderWriterLock( );
    private Socket socket;

    private ILog logger = LogManager.GetLogger( typeof( UdpServer ) );
}

最後に、SystemStatus オブジェクトのプロパティにアクセスする getter と setter を使用してカウントが返されます。

override public int Count1 {
        get { return sysStatus.Count1; }
    }

    override public int Count2 {
        get { return sysStatus.Count2 ; }
    }

    override public int Count3 {
        get { return sysStatus.Count3 ; }
    }

    override public int Count4 {
        get { return sysStatus.Count4 ; }
    }

    override public int Count5 {
        get { return sysStatus.Count5 ; }
    }

各インスタンスは、独自の一意のポートで開始されます。非送信請求メッセージを受信した場合にコールバック関数にブレーク ポイントを設定しましたが、実際にデータを受信することを意図したインスタンス以外のインスタンスでブレークすることはありませんが、すべて同じカウントを返します。

4

1 に答える 1

0

sysStatus を初期化するときは、これを SystemStatus.NullStatus に設定します。これは、静的な SystemStatus インスタンスであると想定しています。この割り当てにより、メモリ内の NullStatus オブジェクトを指すように sysStatus 変数が更新されます。そのオブジェクトのコピーは作成されません。sysStatus 変数を介して値を設定すると、SystemStatus.NullSTAtus が指す同じオブジェクトが更新されます。これは、すべてのインスタンスによって共有される静的オブジェクトです。これを構造体に変更するか、sysStatus をその静的インスタンスに向ける代わりに新しい SystemStatus() を使用することができます。

編集:以下は私の元の答えでした...

あなたの問題の鍵はここにあると思います:

ParseSystemStatus 関数は、UDP メッセージを受信するたびにトリガーされるイベント ハンドラーから呼び出されます。

3 つのインスタンスはすべて、PacketReceived イベントをリッスンするように接続されています。OnPacketReceived メソッドが呼び出され、PacketReceived に格納されているイベントをトリガーすると、それをリッスンするように配線されているすべてのイベント ハンドラーが起動されます。つまり、client_UnsolicitedMessageReceived メソッドは、クラスのインスタンスごとに個別に呼び出されます。

言い換えれば、システムが現在書かれている方法では、1 つの UDP サーバーがあります。パケットを受信するたびに、パケットが受信されたことを SuccinctClass のすべてのインスタンスに通知します。別の動作が必要な場合は、実際に通知したいインスタンスを指定する方法を考え出すか、SuccinctClass のインスタンス内から、特定のパケットを本当に処理するか、別のパケットに任せるかを検出する方法を考え出す必要があります。クラスのインスタンス。

于 2012-07-24T13:41:43.787 に答える