私はここでかなりの問題を抱えています。外部デバイスと通信するための実装を処理するモデルがある 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 ; }
}
各インスタンスは、独自の一意のポートで開始されます。非送信請求メッセージを受信した場合にコールバック関数にブレーク ポイントを設定しましたが、実際にデータを受信することを意図したインスタンス以外のインスタンスでブレークすることはありませんが、すべて同じカウントを返します。