Grupo multicast UDP no Windows Phone 8
OK, este é um que venho tentando descobrir há alguns dias. Temos um aplicativo no Windows Phone 7 em que os telefones ingressam em um grupo de multidifusão e, em seguida, enviam e recebem mensagens para o grupo para conversar entre si. Nota - esta é uma comunicação de telefone para telefone.
Agora eu estou tentando portar este aplicativo para o Windows Phone 8 - usando o recurso 'Converter em Phone 8' no Visual Studio 2012 - até aí tudo bem. Até que eu tente testar o telefone para telefonar para a comunicação. Os aparelhos parecem se juntar ao grupo bem, e eles enviam os datagramas OK. Eles até recebem as mensagens que enviam para o grupo - no entanto, nenhum aparelho recebe uma mensagem de outro aparelho.
Aqui está o código de exemplo da minha página:
// Constructor
public MainPage()
{
InitializeComponent();
}
// The address of the multicast group to join.
// Must be in the range from 224.0.0.0 to 239.255.255.255
private const string GROUP_ADDRESS = "224.0.1.1";
// The port over which to communicate to the multicast group
private const int GROUP_PORT = 55562;
// A client receiver for multicast traffic from any source
UdpAnySourceMulticastClient _client = null;
// Buffer for incoming data
private byte[] _receiveBuffer;
// Maximum size of a message in this communication
private const int MAX_MESSAGE_SIZE = 512;
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
_client = new UdpAnySourceMulticastClient(IPAddress.Parse(GROUP_ADDRESS), GROUP_PORT);
_receiveBuffer = new byte[MAX_MESSAGE_SIZE];
_client.BeginJoinGroup(
result =>
{
_client.EndJoinGroup(result);
_client.MulticastLoopback = true;
Receive();
}, null);
}
private void SendRequest(string s)
{
if (string.IsNullOrWhiteSpace(s)) return;
byte[] requestData = Encoding.UTF8.GetBytes(s);
_client.BeginSendToGroup(requestData, 0, requestData.Length,
result =>
{
_client.EndSendToGroup(result);
Receive();
}, null);
}
private void Receive()
{
Array.Clear(_receiveBuffer, 0, _receiveBuffer.Length);
_client.BeginReceiveFromGroup(_receiveBuffer, 0, _receiveBuffer.Length,
result =>
{
IPEndPoint source;
_client.EndReceiveFromGroup(result, out source);
string dataReceived = Encoding.UTF8.GetString(_receiveBuffer, 0, _receiveBuffer.Length);
string message = String.Format("[{0}]: {1}", source.Address.ToString(), dataReceived);
Log(message, false);
Receive();
}, null);
}
private void Log(string message, bool isOutgoing)
{
if (string.IsNullOrWhiteSpace(message.Trim('\0')))
{
return;
}
// Always make sure to do this on the UI thread.
Deployment.Current.Dispatcher.BeginInvoke(
() =>
{
string direction = (isOutgoing) ? ">> " : "<< ";
string timestamp = DateTime.Now.ToString("HH:mm:ss");
message = timestamp + direction + message;
lbLog.Items.Add(message);
// Make sure that the item we added is visible to the user.
lbLog.ScrollIntoView(message);
});
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
// Don't send empty messages.
if (!String.IsNullOrWhiteSpace(txtInput.Text))
{
//Send(txtInput.Text);
SendRequest(txtInput.Text);
}
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
SendRequest("start now");
}
Para simplesmente testar a pilha UDP, baixei o exemplo do MSDN encontradoAqui e eu testei isso em um par de dispositivos Windows Phone 7 e funciona como esperado. Então eu converti para o Windows Phone 8 e implantei para os meus aparelhos, mais uma vez os dispositivos parecem iniciar sua conexão, e o usuário pode digitar seu nome. No entanto, novamente, os dispositivos não podem ver ou se comunicar com outros dispositivos.
Por fim, implementei um teste de comunicação simples usando a nova implementação do DatagramSocket e, novamente, vejo uma iniciação bem-sucedida, mas nenhuma comunicação entre dispositivos.
Este é o mesmo código por trás da página usando a implementação do socket de datagrama:
// Constructor
public MainPage()
{
InitializeComponent();
}
// The address of the multicast group to join.
// Must be in the range from 224.0.0.0 to 239.255.255.255
private const string GROUP_ADDRESS = "224.0.1.1";
// The port over which to communicate to the multicast group
private const int GROUP_PORT = 55562;
private DatagramSocket socket = null;
private void Log(string message, bool isOutgoing)
{
if (string.IsNullOrWhiteSpace(message.Trim('\0')))
return;
// Always make sure to do this on the UI thread.
Deployment.Current.Dispatcher.BeginInvoke(
() =>
{
string direction = (isOutgoing) ? ">> " : "<< ";
string timestamp = DateTime.Now.ToString("HH:mm:ss");
message = timestamp + direction + message;
lbLog.Items.Add(message);
// Make sure that the item we added is visible to the user.
lbLog.ScrollIntoView(message);
});
}
private void btnSend_Click(object sender, RoutedEventArgs e)
{
// Don't send empty messages.
if (!String.IsNullOrWhiteSpace(txtInput.Text))
{
//Send(txtInput.Text);
SendSocketRequest(txtInput.Text);
}
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
socket = new DatagramSocket();
socket.MessageReceived += socket_MessageReceived;
try
{
// Connect to the server (in our case the listener we created in previous step).
await socket.BindServiceNameAsync(GROUP_PORT.ToString());
socket.JoinMulticastGroup(new Windows.Networking.HostName(GROUP_ADDRESS));
System.Diagnostics.Debug.WriteLine(socket.ToString());
}
catch (Exception exception)
{
throw;
}
}
private async void SendSocketRequest(string message)
{
// Create a DataWriter if we did not create one yet. Otherwise use one that is already cached.
//DataWriter writer;
var stream = await socket.GetOutputStreamAsync(new Windows.Networking.HostName(GROUP_ADDRESS), GROUP_PORT.ToString());
//writer = new DataWriter(socket.OutputStream);
DataWriter writer = new DataWriter(stream);
// Write first the length of the string as UINT32 value followed up by the string. Writing data to the writer will just store data in memory.
// stream.WriteAsync(
writer.WriteString(message);
// Write the locally buffered data to the network.
try
{
await writer.StoreAsync();
Log(message, true);
System.Diagnostics.Debug.WriteLine(socket.ToString());
}
catch (Exception exception)
{
throw;
}
finally
{
writer.Dispose();
}
}
void socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
try
{
uint stringLength = args.GetDataReader().UnconsumedBufferLength;
string msg = args.GetDataReader().ReadString(stringLength);
Log(msg, false);
}
catch (Exception exception)
{
throw;
}
}
Ontem à noite, levei os aparelhos para casa para testá-los na minha rede sem fio doméstica, e eis que recebo uma comunicação de dispositivo bem-sucedida.
Então, para recapitular - meu código herdado do Windows Phone 7 roda bem na minha rede de trabalho. A porta para o Windows Phone 8 (sem alteração real de código) não envia comunicação entre dispositivos. Este código funciona na minha rede doméstica. O código é executado com o depurador anexado e não há sinais de erros ou exceções durante a execução.
Os aparelhos que estou usando são:
Windows Phone 7 - Nokia Lumia 900 (* 2), Nokia Lumia 800 (* 3) Windows Phone 8 - Nokia Lumia 920 (* 1), Nokia Limia 820 (* 2)
Todos eles estão executando o sistema operacional mais recente e estão no modo de desenvolvedor. Ambiente de desenvolvimento é o Windows 8 Enterprise executando o Visual Studio 2012 Professional
Eu não posso falar muito sobre a rede wireless do trabalho - além dos dispositivos Phone 7 não ter nenhum problema.
Quanto à rede sem fio doméstica que eu usei, isso é apenas um roteador básico de banda larga BT com nenhuma das configurações 'out the box' alteradas.
Claramente, há um problema com a maneira como as duas redes estão configuradas, mas também há um problema muito claro com o modo como o Windows Phone 8 implementa mensagens UDP.
Qualquer entrada seria apreciada, pois isso está me deixando louco agora.