Я создал приложение, которое отправляет UDP-сообщение другому приложению, а затем прослушивает ответ UDP-сообщения.Однако происходит самое странное, что я когда-либо видел.В конце концов я обнаружил, что проблема заключается в порядке моего кода, но я не уверен, почему это так.После многих часов я сузил свой код до следующих строк:
Не рабочий код:
UDPSender sender = new UDPSender(destinationIP, portDest, sourceIP, portSource, AgentTypeEnum.User, this);
listener = new UDPListener(sourceIP, portSource, AgentTypeEnum.User, this);
listener.StartListener();
sender.SendUDPOnce(new BytesAndRequestType(Encoding.ASCII.GetBytes(asciiChars), null), successFlag);
Рабочий код:
listener = new UDPListener(sourceIP, portSource, AgentTypeEnum.User, this);
listener.StartListener();
UDPSender sender = new UDPSender(destinationIP, portDest, sourceIP, portSource, AgentTypeEnum.User, this);
sender.SendUDPOnce(new BytesAndRequestType(Encoding.ASCII.GetBytes(asciiChars), null), successFlag);
Вот мой код дляспецифика UDPSender и UDPListener.По сути, все, что он делает, - это оборачивает UDPClient и выполняет специфическое прослушивание и отправку пакетов UDP к и от адресатов.
UDPSender:
namespace Agent
{
public class UDPSender
{
private IPAddress destIpAddress;
private IPAddress sourceIPAddress;
private int destPortNumber;
private int sourcePortNumber;
private byte[] header; // first part of message byte array
private SequenceMapSelector mapper = SequenceMapSelector.Instance;
private Timer udpSendTimer;
IPEndPoint destinationEP;
IPEndPoint sourceEP;
UdpClient sender;
public UDPSender(string destIpAddress, int destPortNumber, string sourceIPAddress, int sourcePortNumber, AgentTypeEnum mt, ParentAgent pa)
{
this.destIpAddress = IPAddress.Parse(destIpAddress);
this.sourceIPAddress = IPAddress.Parse(sourceIPAddress);
header = Encoding.ASCII.GetBytes("Apple!");
// This could have been done with bit shifts and masking
// header[0] = (byte)(0x424f4f425321 >> 40 & 0xFF);
// header[1] = (byte)(0x424f4f425321 >> 32 & 0xFF);
// header[2] = (byte)(0x424f4f425321 >> 24 & 0xFF);
// header[3] = (byte)(0x424f4f425321 >> 16 & 0xFF);
// header[4] = (byte)(0x424f4f425321 >> 8 & 0xFF);
// header[5] = (byte)(0x424f4f425321 & 0xFF);
// Or this as well
// header[0] = (byte)((0x424f4f425321 & 0xFF0000000000) >> 40);
// header[1] = (byte)((0x424f4f425321 << 8 & 0xFF0000000000) >> 40);
// header[2] = (byte)((0x424f4f425321 << 16 & 0xFF0000000000) >> 40);
// header[3] = (byte)((0x424f4f425321 << 24 & 0xFF0000000000) >> 40);
// header[4] = (byte)((0x424f4f425321 << 32 & 0xFF0000000000) >> 40);
// header[5] = (byte)((0x424f4f425321 << 40 & 0xFF0000000000) >> 40);
this.destPortNumber = destPortNumber;
this.sourcePortNumber= sourcePortNumber;
sourceEP = new IPEndPoint(this.sourceIPAddress, sourcePortNumber);
sender = new UdpClient
{
ExclusiveAddressUse = false
};
sender.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sender.Client.Bind(sourceEP);
mapper.CreateSystemGroup(this.destIpAddress, mt, pa); // must create a system group so that when data comes in we can look up the group
}
public byte SendUDPOnce(BytesAndRequestType udpDataAndCommandUsed, bool successFlag) // i think i can just return void
{
byte[] sendbuf = new byte[3 + header.Length + udpDataAndCommandUsed.ASCII_Bytes.Length]; // [0] = lastOctet [1] = sequenceNum;
byte sequenceNum = BuildByteMessage(header, udpDataAndCommandUsed.ASCII_Bytes, sendbuf, (RequestTypeEnum?)udpDataAndCommandUsed.requestType, successFlag); // I should refactor this to just take a CommandParameters.BytesAndRequestEnum
destinationEP = new IPEndPoint(destIpAddress, destPortNumber);
sender.Send(sendbuf, sendbuf.Length, destinationEP);
// Console.WriteLine("Sender: Message sent to the broadcast address: " + toIpAddress + Environment.NewLine + "Sender: contents (first byte is IP_Octet, second is sequenceNumber): " + string.Join(",", sendbuf));
return sequenceNum;
}
public void SendUDPContinuously(BytesAndRequestType udpDataAndCommandUsed, bool successFlag, int delayMiliseconds)
{
udpSendTimer = new Timer(sate => SendUDPOnce(udpDataAndCommandUsed, successFlag), null, 0, delayMiliseconds);
}
public void StopUDPContinuousSend()
{
mapper.DumpDataToFile(destIpAddress);
udpSendTimer.Dispose();
}
private byte BuildByteMessage(byte[] header, byte[] parameterCommand, byte[] destination, RequestTypeEnum? commandEnum, bool successFlag)
{
byte sequenceNum = mapper.CreateNextSequenceByte(destIpAddress, commandEnum);
Buffer.BlockCopy(header, 0, destination, 0, header.Length);
destination[header.Length] = (byte)(commandEnum == null ? RequestTypeEnum.ERROR : commandEnum);
destination[header.Length+1] = sequenceNum;
destination[header.Length + 2] = (byte)(successFlag ? 1: 0);
// add header to parameterCommand
Buffer.BlockCopy(parameterCommand, 0, destination, header.Length + 3, parameterCommand.Length);
return sequenceNum;
}
}
}
UDPListener:
namespace Agent
{
// in this context, the source is the machine that this code is running on. and the destination is the IP address of the agent machine.
public class UDPListener
{
IPAddress ipAddressSource;
int listenPort;
private SequenceMapSelector sequenceMap = SequenceMapSelector.Instance;
UdpClient listener;
IPEndPoint endPoint;
IPEndPoint sendersEndPoint;
AgentTypeEnum agentTypeOfCurrentMachine;
ParentAgent pa;
public UDPListener(string ipAddressOfSource, int portSource, AgentTypeEnum agentTypeOfCurrentMachine, ParentAgent pa)
{
this.agentTypeOfCurrentMachine = agentTypeOfCurrentMachine;
ipAddressSource = IPAddress.Parse(ipAddressOfSource); // need to listen to the IP address this UDP message is coming FROM
listenPort = portSource; // need to listen to the the port that the UDP message was sent TO
this.pa = pa;
}
public void StartListener()
{
listener = new UdpClient
{
ExclusiveAddressUse = false
};
listener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
endPoint = new IPEndPoint(ipAddressSource, listenPort); //new IPEndPoint(IPAddress.Any, listenPort); this might allow me not to know the IP of this local device!
listener.Client.Bind(endPoint);
try
{
listener.BeginReceive(new AsyncCallback(Receive), null);
}
catch (Exception e)
{
ErrorLogger.WriteExceptionToLog(e);
listener.Close();
}
finally
{
}
}
private void Receive(IAsyncResult res)
{
byte[] bytes = listener.EndReceive(res, ref sendersEndPoint);
listener.BeginReceive(new AsyncCallback(Receive), null);
if (sequenceMap.FindSystemGroup(sendersEndPoint.Address) == null)
{
// if there was no system group for this type of agent, then add a system group for it.
// are both the AgentType and requestType in bytes[6]??? this seems incorrect
sequenceMap.CreateSystemGroup(sendersEndPoint.Address, agentTypeOfCurrentMachine, pa); // in this case we don't want (AgentTypeEnum)bytes[6] since this would give us the agent type of the sender machine
sequenceMap.CreateNextSequenceByte(sendersEndPoint.Address, (RequestTypeEnum)bytes[6]); // in this case we don't want (RequestTypeEnum)bytes[6] since this would give us the agent type of the sender machine
}
sequenceMap.AddDataToLookup(sendersEndPoint.Address, sendersEndPoint.Port, bytes[7], bytes);
Console.WriteLine("Received" + Environment.NewLine);
}
}
}
Примечание: оба UDPClients (отправитель и слушатель) привязаны к одному и тому же IP, но с разными номерами портов.Никаких исключений не выбрасывается.Моя теория состоит в том, что сборка мусора может вступить в игру?
Ответ, который я ищу, состоит в том, чтобы объяснить, почему UDPListener никогда не получает никаких сообщений UDP, когда сначала создается мой UDPSender, но если я делаю это наоборотзаказать это работает нормально.