| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using System;
- using System.Net;
- using System.Net.Sockets;
- using System.Text;
- using System.Threading;
- public class BleUDP : MonoBehaviour
- {
- public static BleUDP ins; //单例记录
- readonly string localIP = "127.0.0.1"; //本地IP
- readonly int myPort = 8001; //自身的注册端口
- readonly int targetPort = 8000; //发消息的目标端口
- Socket client; //UDP对象
- float noneMsgTime = 0; //多久没收到字节消息了
- Queue<byte[]> byteQueue = new Queue<byte[]>(); //接收信息的线程把字节信息放这里
- Queue<byte[]> byteMainQueue = new Queue<byte[]>(); //主线程从byteQueue中取出数据后放在这里,供主线程update使用
- public Action OnConnected;
- public Action OnConnectionFailed;
- public Action<byte[]> OnCharacteristicChanged;
- public Action OnScanEnded;
- [NonSerialized] public BluetoothStatusEnum bluetoothStatusEnum = BluetoothStatusEnum.Connect;
- void Awake()
- {
- if (ins)
- {
- Destroy(this.gameObject);
- return;
- }
- ins = this;
- DontDestroyOnLoad(this.gameObject);
- }
- bool _inited;
- void Init()
- {
- if (_inited) return;
- _inited = true;
- client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
- client.Bind(new IPEndPoint(IPAddress.Parse(localIP), myPort));
- /*
- C# UDP Socket ReceiveFrom 远程主机强迫关闭了一个现有的连接。
- (经过反复研究,下述情况的原因终于搞清楚了,是"ICMP port unreachable"的问题,即:若向一个没有相应UDP监听端口的本机地址(比如127.0.0.1)发送UDP数据包,会回复ICMP port unreachable包,而这个包会被C#的UDP Socket ReceiveFrom函数得到,并报错为“远程主机强迫关闭了一个现有连接”!)
- (而为什么向存在的另一个ip(另一台主机)发送不会报错?因为防火墙!win10的防火墙把外部回复的ICMP port unreachable给屏蔽掉了。经实验,把防火墙关掉后,就会出现上述报错了。)
- (而为什么向一个不存在的ip地址发送不会报错?因为主机不存在,所以不会回复ICMP port unreachable)
- */
- //配置socket参数,避免ICMP包导致的异常
- uint IOC_IN = 0x80000000;
- uint IOC_VENDOR = 0x18000000;
- uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
- client.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
- Thread threadReciveMsg = new Thread(ReciveMsg);
- threadReciveMsg.Start();
- }
- void OnDestroy()
- {
- if (ins == this) ins = null;
- if (client != null) client.Close();
- }
- void Update()
- {
- lock (byteQueue)
- {
- while (byteQueue.Count > 0)
- {
- byteMainQueue.Enqueue(byteQueue.Dequeue());
- }
- }
- if (bluetoothStatusEnum == BluetoothStatusEnum.Connecting)
- {
- if (noneMsgTime > 5)
- {
- bluetoothStatusEnum = BluetoothStatusEnum.ConnectFail;
- EmitOnConnectionFailed();
- return;
- }
- else if (byteMainQueue.Count > 0)
- {
- bluetoothStatusEnum = BluetoothStatusEnum.ConnectSuccess;
- EmitOnConnected();
- }
- }
- else if (bluetoothStatusEnum == BluetoothStatusEnum.ConnectSuccess)
- {
- if (noneMsgTime > 5)
- {
- bluetoothStatusEnum = BluetoothStatusEnum.ConnectFail;
- EmitOnConnectionFailed();
- }
- }
- else
- {
- byteMainQueue.Clear();
- return;
- }
- if (byteMainQueue.Count == 0)
- {
- noneMsgTime += Time.deltaTime;
- return;
- }
- noneMsgTime = 0;
- while (byteMainQueue.Count > 0)
- {
- EmitOnCharacteristicChanged(byteMainQueue.Dequeue());
- }
- }
- public void SendMsg(string data)
- {
- Debug.LogWarning("sendMsgToBle: " + data);
- EndPoint point = new IPEndPoint(IPAddress.Parse(localIP), targetPort);
- client.SendTo(Encoding.UTF8.GetBytes(data), point);
- }
- void ReciveMsg()
- {
- while (true)
- {
- EndPoint point = new IPEndPoint(IPAddress.Any, 0);
- byte[] buffer = new byte[1024];
- int length = client.ReceiveFrom(buffer, ref point);
- if (!point.ToString().EndsWith(targetPort.ToString())) continue;
- if (length <= 0) continue;
- byte[] bytes = new byte[length];
- Array.Copy(buffer, bytes, length);
- lock (byteQueue)
- {
- byteQueue.Enqueue(bytes);
- }
- }
- }
- public void ScanNearbyDevices()
- {
- EmitOnScanEnded();
- }
- public void Connect()
- {
- Init();
- noneMsgTime = 0;
- bluetoothStatusEnum = BluetoothStatusEnum.Connecting;
- SendMsg("M");
- }
- public void Disconnect()
- {
- bluetoothStatusEnum = BluetoothStatusEnum.Connect;
- }
- void EmitOnConnected()
- {
- try
- {
- OnConnected?.Invoke();
- }
- catch (Exception) { }
- }
- void EmitOnConnectionFailed()
- {
- try
- {
- OnConnectionFailed?.Invoke();
- }
- catch (Exception) { }
- }
- void EmitOnCharacteristicChanged(byte[] bytes)
- {
- try
- {
- OnCharacteristicChanged?.Invoke(bytes);
- }
- catch (Exception) { }
- }
- void EmitOnScanEnded()
- {
- try
- {
- OnScanEnded?.Invoke();
- }
- catch (Exception) { }
- }
- }
|