Unity Android程序,想实现一个局域网会议程序。
一个程序创建好房间后,需要让其他客户端知道,就需要不断往局域网发消息
开始想使用广播,后来改成组播。这里说一下这两种方式吧
一、广播
广播会往局域网所有客户端发送一次消息。
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
_socket.Bind(new IPEndPoint(GetIpAddress(), port));
private IPAddress GetIpAddress()
{
string hostName = Dns.GetHostName();
IPAddress[] _ipAddress = Dns.GetHostEntry(hostName).AddressList;
foreach (IPAddress _IPAddress in _ipAddress)
{
if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
{
ip = _IPAddress.ToString();
return _IPAddress;
}
}
Debug.LogError("没找到IP");
return null;
}
Socket需要设置广播权限
Broadcastpoint = new IPEndPoint(IPAddress.Broadcast, port);
byte[] _data = Encoding.UTF8.GetBytes(data);
_socket.SendTo(_data, Broadcastpoint);
发送消息,需要不停发送,所以要一个定时循环
EndPoint point = new IPEndPoint(IPAddress.Any, port);
byte[] message = new byte[1024];
int length = _socket.ReceiveFrom(message, ref point);
if (length > 0)
{
byte[] getmessage = new byte[length];
Array.Copy(message, getmessage, length);
string _message = Encoding.UTF8.GetString(getmessage);
Debug.Log(_message);
}
接收消息
二、组播
组播比广播方便,因为是做会议程序,所以只需要把参议人员接收的组播ip设置一致,并把数据发送里面就可以了。不需要自己管理成员。而且节省宽带,不需要循环发给每个成员
public UDPServer()
{
sendclient = new UdpClient();
}
public void Send(string multicastIp , params string[] data)
{
try
{
iep = new IPEndPoint(IPAddress.Parse(multicastIp), port);
string _data = AppendData(data);
Debug.LogError(_data);
byte[] b = Encoding.UTF8.GetBytes(_data);
sendclient.Send(b, b.Length, iep);
}
catch (Exception e)
{
Debug.LogError(e);
}
}
因为组播ip是需要改变的,搜索房间需要一个组播ip , 房间通信又需要一个,所以ip不能定死。
recevieclient = new UdpClient(port);
iep = new IPEndPoint(IPAddress.Parse(multicastIp), port);
recevieclient.JoinMulticastGroup(IPAddress.Parse(multicastIp));
Thread _receiveThread = new Thread(new ThreadStart(Received));
_receiveThread.IsBackground = true;
_receiveThread.Start();
public void Received()
{
recevie = true;
while (recevie)
{
try
{
byte[] message = recevieclient.Receive(ref iep);
string _message = Encoding.UTF8.GetString(message);
UnityThread.Instance.AddAction(delegate
{
MessageManager.Instance.SplitMessage(_message , localIP);
});
}
catch(Exception e)
{
Debug.LogError(e);
}
}
}
接收端只要和发送端保持ip 端口一致就行
三、Android 组播问题
Android如果需要接收组播是需要组播锁的
package com.lightin.lightinarforunity;
import android.content.Context;
import android.net.wifi.WifiManager;
public class M_MulticastLock {
private WifiManager.MulticastLock multicastLock;
private Context context;
private static M_MulticastLock instance;
public static M_MulticastLock Instance(){
if(instance == null)
instance = new M_MulticastLock();
return instance;
}
public void Init(Context context)
{
this.context = context;
WifiManager wifiManager=(WifiManager)context.getSystemService(Context.WIFI_SERVICE);
multicastLock=wifiManager.createMulticastLock("multicast.test");
}
public void allowMulticast(){
multicastLock.acquire();
}
public void closeMulticast(){
multicastLock.release();
}
}
单例调用这个类,我是每帧都会调用allowMulticast。只能在主线程调用,不然会报错。
权限