Я делаю несколько тестов mDNS и использую два сокета: один для отправки запросов mDNS и один для прослушивания сети (этот асинхронный). Иногда я вижу ответы, которые не получены запрашивающим сокетом просто потому, что адрес назначения — 224.0.0.251. Дело в том, что когда время ожидания синхронного сокета истекает, асинхронный сокет получает перехваченные данные только после истечения времени ожидания другого. Почему это? Спасибо.
Для запросов у меня есть функция FindIP(), а для прослушивания у меня есть класс ClassSniffer. См. код ниже.
private void FindIP( int idx_target )
{
string TargetName = textBox_Name_array[ idx_target ].Text.Trim();
string TargetSuffix = "local";
if( TargetName.Length > 0xFF ) TargetName = TargetName.Substring( 0, 0xFF );
Socket sock = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
sock.SendTimeout = 3000;
sock.ReceiveTimeout = Convert.ToInt32( numericUpDown_RxTimeOut.Value ) * 1000;
IPEndPoint endPoint = new IPEndPoint( IPAddress.Parse( mDNS_addr ), mDNS_port );
byte[] buffer_send, buffer_recv = new byte[ 1024 ];
buffer_send = new byte[ 0 ]
.Concat( BitConverter.GetBytes( cnt_trans ).Take( 2 ).Reverse().ToArray() ) // Transaction ID
.Concat( BitConverter.GetBytes( 0 ).Take( 2 ).Reverse().ToArray() ) // Flags
.Concat( BitConverter.GetBytes( 1 ).Take( 2 ).Reverse().ToArray() ) // Number of questions
.Concat( BitConverter.GetBytes( 0 ).Take( 2 ).Reverse().ToArray() ) // Number of answers
.Concat( BitConverter.GetBytes( 0 ).Take( 2 ).Reverse().ToArray() ) // Number of authority resource records
.Concat( BitConverter.GetBytes( 0 ).Take( 2 ).Reverse().ToArray() ) // Number of additional resource records
.Concat( new byte[] { Convert.ToByte( TargetName.Length ) } ).Concat( Encoding.ASCII.GetBytes( TargetName ) )
.Concat( new byte[] { Convert.ToByte( TargetSuffix.Length ) } ).Concat( Encoding.ASCII.GetBytes( TargetSuffix ) )
.Concat( new byte[] { 0 } ) // Terminator
.Concat( BitConverter.GetBytes( 1 ).Take( 2 ).Reverse().ToArray() ) // Type (A record)
.Concat( BitConverter.GetBytes( 1 ).Take( 2 ).Reverse().ToArray() ) // Class IN
.ToArray();
// TX
sock.SendTo( buffer_send, endPoint );
// RX
try
{
sock.Receive( buffer_recv );
...
}
...
}
private class ClassSniffer
{
public ClassSniffer( Form_Main main_instance )
{
this.main_instance = main_instance;
buff_data = new byte[ 1024 ];
recv_done = false;
timer_socket = new System.Timers.Timer();
timer_socket.SynchronizingObject = main_instance;
timer_socket.Elapsed += TimerAttenElapsed;
timer_socket.Interval = 100;
timer_socket.Start();
sock_conn = new Socket( AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
sock_conn.SetSocketOption( SocketOptionLevel.Udp, SocketOptionName.NoDelay, 1 );
sock_conn.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1 );
sock_conn.Bind( new IPEndPoint( IPAddress.Any, Form_Main.mDNS_port ) );
sock_conn.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 0 ); // 0
sock_conn.SetSocketOption( SocketOptionLevel.IP, SocketOptionName.AddMembership
, new MulticastOption( IPAddress.Parse( Form_Main.mDNS_addr ) ) );
SnifferRecieve();
}
private Form_Main main_instance;
private System.Timers.Timer timer_socket;
private Mutex socket_mutex = new Mutex();
private Socket sock_conn;
private byte[] buff_data = new byte[ 1024 ];
private int recv_size = 0;
private bool recv_done = false;
private void SnifferRecieve()
{
try
{
IPEndPoint LocalIPEndPoint = new IPEndPoint( IPAddress.Any, Form_Main.mDNS_port );
EndPoint LocalEndPoint = (EndPoint)LocalIPEndPoint;
StateObject state = new StateObject();
state.socket_work = sock_conn;
sock_conn.BeginReceiveFrom( state.buffer, 0, state.buffer.Length, 0, ref LocalEndPoint, new AsyncCallback( SnifferReceiveCallback ), state );
}
catch( Exception excp )
{
string err_msg = excp.ToString();
}
}
private void SnifferReceiveCallback( IAsyncResult async_res )
{
IPEndPoint LocalIPEndPoint = new IPEndPoint( IPAddress.Any, Form_Main.mDNS_port );
EndPoint LocalEndPoint = (EndPoint)LocalIPEndPoint;
StateObject async_state = (StateObject)async_res.AsyncState;
Socket socket_client = async_state.socket_work;
int async_recv_size = socket_client.EndReceiveFrom( async_res, ref LocalEndPoint );
socket_client.BeginReceiveFrom( async_state.buffer, 0, async_state.buffer.Length, 0, ref LocalEndPoint
, new AsyncCallback( SnifferReceiveCallback ), async_state );
socket_mutex.WaitOne();
recv_size = async_recv_size;
async_state.buffer.CopyTo( buff_data, 0 );
recv_done = true;
socket_mutex.ReleaseMutex();
}
private void TimerAttenElapsed( object source, ElapsedEventArgs e )
{
socket_mutex.WaitOne();
if( recv_done )
{
main_instance.SnifferWriteData( buff_data, recv_size ); // displays data in a textBox
recv_done = false;
}
socket_mutex.ReleaseMutex();
}
}