/// <summary> /// This should be called in connection thread. Real send data to server. The sending will NOT be done immediately, and we should NOT reuse data before onComplete. /// </summary> /// <param name="data">data to send.</param> /// <param name="cnt">data count in bytes.</param> /// <param name="onComplete">this will be called in some other thread.</param> public void SendRaw(byte[] data, int cnt, Action <bool> onComplete) { _LastSendTick = System.Environment.TickCount; if (_Socket != null) { try { if (_BroadcastEP != null) { _Socket.BeginSendTo(data, 0, cnt, SocketFlags.None, _BroadcastEP, ar => { bool success = false; try { _Socket.EndSendTo(ar); success = true; } catch (Exception e) { PlatDependant.LogError(e); } if (onComplete != null) { onComplete(success); } }, null); return; } else { _Socket.BeginSend(data, 0, cnt, SocketFlags.None, ar => { bool success = false; try { _Socket.EndSend(ar); success = true; } catch (Exception e) { PlatDependant.LogError(e); } if (onComplete != null) { onComplete(success); } }, null); return; } } catch (Exception e) { PlatDependant.LogError(e); } } if (onComplete != null) { onComplete(false); } }
/// <summary> /// This should be called in connection thread. Real send data to server. The sending will NOT be done immediately, and we should NOT reuse data before onComplete. /// </summary> /// <param name="data">data to send.</param> /// <param name="cnt">data count in bytes.</param> /// <param name="onComplete">this will be called in some other thread.</param> public void SendRaw(byte[] data, int cnt, Action <bool> onComplete) { if (_Socket != null) { try { _Socket.BeginSend(data, 0, cnt, SocketFlags.None, ar => { bool success = false; try { _Socket.EndSend(ar); success = true; } catch (Exception e) { PlatDependant.LogError(e); } if (onComplete != null) { onComplete(success); } }, null); return; } catch (Exception e) { PlatDependant.LogError(e); } } if (onComplete != null) { onComplete(false); } }
public object Read(out uint seq, out uint sseq, out uint type) { try { while (_Client != null && _Client.IsConnectionAlive) { _Splitter.ReadBlock(); if (_PendingRead.Obj != null) { var obj = _PendingRead.Obj; seq = _PendingRead.Seq; sseq = _PendingRead.SSeq; type = _PendingRead.Type; _PendingRead.Obj = null; return(obj); } } } catch (Exception e) { PlatDependant.LogError(e); } seq = 0; sseq = 0; type = 0; return(null); }
protected void FireReceiveBlock(NativeBufferStream buffer, int size, uint type, uint flags, uint seq, uint sseq) { #if DEBUG_PERSIST_CONNECT PlatDependant.LogInfo(string.Format("Data Received, length {0}, type {1}, flags {2:x}, seq {3}, sseq {4}. (from {5})", size, type, flags, seq, sseq, this.GetType().Name)); #endif //buffer.Seek(0, SeekOrigin.Begin); OnReceiveBlock(buffer, size, type, flags, seq, sseq); }
public void StartConnect() { if (!IsConnectionAlive) { _ConnectWorkRunning = true; PlatDependant.RunBackground(prog => ConnectWork()); } }
protected override void ConnectWork() { try { var address4 = IPAddress.Any; _Socket = new Socket(address4.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _Socket.Bind(new IPEndPoint(address4, _Port)); _Socket.Listen(CONST.MAX_SERVER_PENDING_CONNECTIONS); var address6 = IPAddress.IPv6Any; _Socket6 = new Socket(address6.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _Socket6.Bind(new IPEndPoint(address6, _Port)); _Socket6.Listen(CONST.MAX_SERVER_PENDING_CONNECTIONS); BeginAccept4(); BeginAccept6(); while (!_ConnectWorkCanceled) { _HaveDataToSend.WaitOne(); } //_Socket.Shutdown(SocketShutdown.Both); //_Socket6.Shutdown(SocketShutdown.Both); } catch (ThreadAbortException) { Thread.ResetAbort(); } catch (Exception e) { PlatDependant.LogError(e); } finally { _ConnectWorkRunning = false; _ConnectWorkCanceled = false; if (_PreDispose != null) { _PreDispose(this); } if (_Socket != null) { _Socket.Close(); _Socket = null; } if (_Socket6 != null) { _Socket6.Close(); _Socket6 = null; } // set handlers to null. _OnReceive = null; _OnSend = null; _OnSendComplete = null; _PreDispose = null; } }
private void Init(string url, uint conv) { if (conv == 0) { PlatDependant.LogError("KCP conversation id should not be 0."); } _Connection = new UDPClient(url); _Conv = conv; _ConnectionHandle = GCHandle.Alloc(_Connection); _KCP = KCPLib.kcp_create(conv, (IntPtr)_ConnectionHandle); _KCP.kcp_setoutput(Func_KCPOutput); _KCP.kcp_nodelay(1, 10, 2, 1); // set minrto to 10? _Connection.UpdateInterval = 10; _Connection.PreDispose = _con => DisposeSelf(); _Connection.OnReceive = (data, cnt, sender) => _KCP.kcp_input(data, cnt); _Connection.OnSend = (data, cnt) => { if (cnt > CONST.MTU) { int offset = 0; var buffer = BufferPool.GetBufferFromPool(); while (cnt > CONST.MTU) { Buffer.BlockCopy(data, offset, buffer, 0, CONST.MTU); _KCP.kcp_send(buffer, CONST.MTU); cnt -= CONST.MTU; offset += CONST.MTU; } if (cnt > 0) { Buffer.BlockCopy(data, offset, buffer, 0, cnt); _KCP.kcp_send(buffer, cnt); } BufferPool.ReturnBufferToPool(buffer); } else { _KCP.kcp_send(data, cnt); } return(true); }; _Connection.OnUpdate = _con => { _KCP.kcp_update((uint)Environment.TickCount); int recvcnt = _KCP.kcp_recv(_RecvBuffer, CONST.MTU); if (_OnReceive != null) { if (recvcnt > 0) { _OnReceive(_RecvBuffer, recvcnt, _Connection.RemoteEndPoint); } } }; }
public KCPConsultClient(string url) : base(url, 1) { _Conv = 0; _Connection.OnUpdate = _con => { _KCP.kcp_update((uint)Environment.TickCount); int recvcnt = _KCP.kcp_recv(_RecvBuffer, CONST.MTU); if (_Conv == 0) { if (recvcnt >= 4) { uint conv = 0; if (BitConverter.IsLittleEndian) { conv = BitConverter.ToUInt32(_RecvBuffer, 0); } else { for (int i = 0; i < 4; ++i) { conv <<= 8; conv += _RecvBuffer[i]; } } if (conv == 0 || conv == 1) { PlatDependant.LogError("KCP conversation id should not be 0 or 1 (with Consult)."); throw new ArgumentException("KCP conversation id should not be 0 or 1 (with Consult)."); } _KCP.kcp_release(); _Conv = conv; _KCP = KCPLib.kcp_create(conv, (IntPtr)_ConnectionHandle); _KCP.kcp_setoutput(Func_KCPOutput); _KCP.kcp_nodelay(1, 10, 2, 1); _Connection.HoldSending = false; } } else { if (_OnReceive != null) { if (recvcnt > 0) { _OnReceive(_RecvBuffer, recvcnt, _Connection.RemoteEndPoint); } } } }; _Connection.PreStart = _con => { var guid = _ConnectionGUID.ToByteArray(); _KCP.kcp_send(guid, guid.Length); }; _Connection.HoldSending = true; }
public void SetConv(uint conv) { if (_Ready) { PlatDependant.LogError("Can not change conv. Please create another one."); } else { _Conv = conv; _KCP = KCPLib.kcp_create(conv, (IntPtr)_InfoHandle); _Ready = true; _KCP.kcp_setoutput(Func_KCPOutput); _KCP.kcp_nodelay(1, 10, 2, 1); // set minrto to 10? } }
private static int KCPOutput(IntPtr buf, int len, KCPLib.Connection kcp, IntPtr user) { try { var gchandle = (GCHandle)user; var info = gchandle.Target as KCPServerConnectionInfo; if (info != null && info.EP != null) { var buffer = BufferPool.GetBufferFromPool(len); Marshal.Copy(buf, buffer, 0, len); info.Server._Connection.SendRaw(buffer, len, info.EP, success => BufferPool.ReturnBufferToPool(buffer)); } } catch (Exception e) { PlatDependant.LogError(e); } return(0); }
private static int KCPOutput(IntPtr buf, int len, KCPLib.Connection kcp, IntPtr user) { try { var gchandle = (GCHandle)user; var connection = gchandle.Target as UDPClient; if (connection != null) { var buffer = BufferPool.GetBufferFromPool(len); Marshal.Copy(buf, buffer, 0, len); connection.SendRaw(buffer, len, success => BufferPool.ReturnBufferToPool(buffer)); } } catch (Exception e) { PlatDependant.LogError(e); } return(0); }
protected void WriteWork(TaskProgress prog) { try { while (_HaveDataToSend.WaitOne()) { try { if (_Connection == null || !_Connection.IsConnectionAlive || _WriteDone) { return; } PendingSendData pending; while (_PendingSend.TryDequeue(out pending)) { if (pending._Req != null) { pending._Req.Send(_Connection); } else if (pending._Raw != null) { _Connection.Write(pending._Raw); } } } catch (ThreadAbortException) { } catch (Exception e) { PlatDependant.LogError(e); } } } catch (ThreadAbortException) { Thread.ResetAbort(); } catch (Exception e) { PlatDependant.LogError(e); } }
public void BeginReceive() { ReceiveCount = 0; ReceiveResult = LocalSocket.BeginReceiveFrom(ReceiveData, 0, CONST.MTU, SocketFlags.None, ref RemoteEP, ar => { try { ReceiveCount = LocalSocket.EndReceiveFrom(ar, ref RemoteEP); } catch (Exception e) { if (ParentServer.IsConnectionAlive) { ParentServer._ConnectWorkCanceled = true; PlatDependant.LogError(e); } } ParentServer._HaveDataToSend.Set(); }, null); }
public override object Read(uint type, NativeBufferStream buffer, int offset, int cnt) { Google.Protobuf.MessageParser parser; DataParsers.TryGetValue(type, out parser); if (parser != null) { try { buffer.Seek(offset, SeekOrigin.Begin); buffer.SetLength(offset + cnt); var rv = parser.ParseFrom(buffer); return(rv); } catch (Exception e) { PlatDependant.LogError(e); } } return(null); }
public override void ReadBlock() { while (true) { // Read Each Tag-Field if (_CodedInputStream.IsAtEnd) { return; } if (_Type == 0) { // Determine the start of a message. while (_Tag == 0) { try { if (_CodedInputStream.IsAtEnd) { return; } _Tag = _CodedInputStream.ReadTag(); } catch (Google.Protobuf.InvalidProtocolBufferException e) { PlatDependant.LogError(e); } catch (InvalidOperationException e) { // this means the stream is closed. so we ignore the exception. //PlatDependant.LogError(e); return; } catch (Exception e) { PlatDependant.LogError(e); return; } } } else { // The Next tag must follow try { _Tag = _CodedInputStream.ReadTag(); if (_Tag == 0) { ResetReadBlockContext(); continue; } } catch (Exception e) { PlatDependant.LogError(e); ResetReadBlockContext(); continue; } } try { // Tag got. int seq = Google.Protobuf.WireFormat.GetTagFieldNumber(_Tag); var ttype = Google.Protobuf.WireFormat.GetTagWireType(_Tag); if (seq == 1 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { ResetReadBlockContext(); _Type = _CodedInputStream.ReadUInt32(); } else if (_Type != 0) { if (seq == 2 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { _Flags = _CodedInputStream.ReadUInt32(); } else if (seq == 3 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { _Seq = _CodedInputStream.ReadUInt32(); } else if (seq == 4 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { _SSeq = _CodedInputStream.ReadUInt32(); } else if (seq == 5 && ttype == Google.Protobuf.WireFormat.WireType.LengthDelimited) { _Size = _CodedInputStream.ReadLength(); if (_Size >= 0) { if (_Size > CONST.MAX_MESSAGE_LENGTH) { PlatDependant.LogError("We got a too long message. We will drop this message and treat it as an error message."); _CodedInputStream.SkipRawBytes(_Size); FireReceiveBlock(null, 0, _Type, _Flags, _Seq, _SSeq); } else { _ReadBuffer.Clear(); _CodedInputStream.ReadRawBytes(_ReadBuffer, _Size); FireReceiveBlock(_ReadBuffer, _Size, _Type, _Flags, _Seq, _SSeq); } } else { FireReceiveBlock(null, 0, _Type, _Flags, _Seq, _SSeq); } ResetReadBlockContext(); return; } } // else means the first field(type) has not been read yet. _Tag = 0; } catch (InvalidOperationException e) { // this means the stream is closed. so we ignore the exception. //PlatDependant.LogError(e); return; } catch (Exception e) { PlatDependant.LogError(e); ResetReadBlockContext(); } } }
public PersistentConnectionRequestFactory(ObjClient con) : base(con) { _ShouldLock = true; PlatDependant.RunBackground(ReadWork); PlatDependant.RunBackground(WriteWork); }
protected void Update() { object readobj = null; uint type, seq, sseq; while ((readobj = Read(out seq, out sseq, out type)) != null) { uint reqseq; uint respseq; if (_Connection.IsServer) { reqseq = sseq; respseq = seq; } else { reqseq = seq; respseq = sseq; } if (reqseq != 0) { if (_ShouldLock) { lock (_PendingRequests) { CheckPendingRequests(readobj, type, reqseq, respseq); } } else { CheckPendingRequests(readobj, type, reqseq, respseq); } } else { if (PushMessageCount >= CONST.MAX_QUEUED_MESSAGE) { PlatDependant.LogError("To many unhandled push messages. Do you forget to check push messages?"); while (PushMessageCount >= CONST.MAX_QUEUED_MESSAGE) { PersistentConnectionResponseData oldmess; if (!TryDequeuePushMessage(out oldmess)) { break; } } } //else { if (OnFilterMessage == null || OnFilterMessage(type, respseq, readobj)) { EnqueuePushMessage(new PersistentConnectionResponseData() { RespDataType = type, RespSeq = respseq, Result = readobj, }); } } } } }
public void SendRaw(byte[] data, int cnt, IPEndPoint ep, Action <bool> onComplete) { if (_ListenBroadcast) { int curVer = 0; if (_KnownRemotesS != null) { curVer = _KnownRemotesS.Version; } int rver = 0; if (_KnownRemotes != null) { rver = _KnownRemotes.Version; } if (rver > curVer) { _KnownRemotesS = System.Threading.Interlocked.Exchange(ref _KnownRemotes, _KnownRemotesS); } Socket knowSocket = null; if (_KnownRemotesS != null) { KnownRemote remote; if (_KnownRemotesS.Remotes.TryGetValue(ep.Address, out remote)) { knowSocket = remote.LocalSocket; remote.LastTick = Environment.TickCount; _KnownRemotesS.Remotes[ep.Address] = remote; } } if (knowSocket != null) { try { knowSocket.BeginSendTo(data, 0, cnt, SocketFlags.None, ep, ar => { bool success = false; try { knowSocket.EndSendTo(ar); success = true; } catch (Exception e) { PlatDependant.LogError(e); } if (onComplete != null) { onComplete(success); } }, null); return; } catch (Exception e) { PlatDependant.LogError(e); } } } else { if (ep.AddressFamily == AddressFamily.InterNetworkV6) { if (_Socket6 != null) { try { _Socket6.BeginSendTo(data, 0, cnt, SocketFlags.None, ep, ar => { bool success = false; try { _Socket6.EndSendTo(ar); success = true; } catch (Exception e) { PlatDependant.LogError(e); } if (onComplete != null) { onComplete(success); } }, null); return; } catch (Exception e) { PlatDependant.LogError(e); } } } else { if (_Socket != null) { try { _Socket.BeginSendTo(data, 0, cnt, SocketFlags.None, ep, ar => { bool success = false; try { _Socket.EndSendTo(ar); success = true; } catch (Exception e) { PlatDependant.LogError(e); } if (onComplete != null) { onComplete(success); } }, null); return; } catch (Exception e) { PlatDependant.LogError(e); } } } } if (onComplete != null) { onComplete(false); } }
protected virtual void ConnectWork() { try { if (_Url != null) { bool isMulticastOrBroadcast = false; int port = 0; Uri uri = new Uri(_Url); port = uri.Port; var addresses = Dns.GetHostAddresses(uri.DnsSafeHost); if (addresses != null && addresses.Length > 0) { var address = addresses[0]; if (address.AddressFamily == AddressFamily.InterNetwork) { if (address.Equals(IPAddress.Broadcast)) { isMulticastOrBroadcast = true; } else { var firstb = address.GetAddressBytes()[0]; if (firstb >= 224 && firstb < 240) { isMulticastOrBroadcast = true; } } } else if (address.AddressFamily == AddressFamily.InterNetworkV6) { if (address.IsIPv6Multicast) { isMulticastOrBroadcast = true; } } _Socket = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); if (isMulticastOrBroadcast) { _Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); if (address.AddressFamily == AddressFamily.InterNetworkV6) { #if NET_STANDARD_2_0 || NET_4_6 // Notice: it is a pitty that unity does not support ipv6 multicast. (Unity 5.6) _Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(address)); _Socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive, 5); #endif _Socket.Bind(new IPEndPoint(IPAddress.IPv6Any, 0)); } else { if (!address.Equals(IPAddress.Broadcast)) { _Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(address, IPAddress.Any)); _Socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 5); } _Socket.Bind(new IPEndPoint(IPAddress.Any, 0)); } _BroadcastEP = new IPEndPoint(address, port); } else { _Socket.Connect(address, port); } } } if (_Socket != null) { if (_PreStart != null) { _PreStart(this); } byte[] receivebuffer = new byte[CONST.MTU]; int receivecnt = 0; EndPoint broadcastRespEP; if (_BroadcastEP != null && _BroadcastEP.AddressFamily == AddressFamily.InterNetworkV6) { broadcastRespEP = new IPEndPoint(IPAddress.IPv6Any, 0); } else { broadcastRespEP = new IPEndPoint(IPAddress.Any, 0); } Action BeginReceive = () => { if (_BroadcastEP != null) { _Socket.BeginReceiveFrom(receivebuffer, 0, CONST.MTU, SocketFlags.None, ref broadcastRespEP, ar => { try { receivecnt = _Socket.EndReceiveFrom(ar, ref broadcastRespEP); } catch (Exception e) { if (IsConnectionAlive) { _ConnectWorkCanceled = true; PlatDependant.LogError(e); } } _HaveDataToSend.Set(); }, null); } else { _Socket.BeginReceive(receivebuffer, 0, CONST.MTU, SocketFlags.None, ar => { try { receivecnt = _Socket.EndReceive(ar); } catch (Exception e) { if (IsConnectionAlive) { _ConnectWorkCanceled = true; PlatDependant.LogError(e); } } _HaveDataToSend.Set(); }, null); } }; if (_OnReceive != null) { BeginReceive(); } while (!_ConnectWorkCanceled) { if (_OnReceive != null) { if (receivecnt > 0) { if (_BroadcastEP != null && _WaitForBroadcastResp) { _OnReceive(receivebuffer, receivecnt, broadcastRespEP); receivecnt = 0; BeginReceive(); } else { if (_BroadcastEP != null) { _Socket.Connect(broadcastRespEP); _BroadcastEP = null; } _OnReceive(receivebuffer, receivecnt, _Socket.RemoteEndPoint); receivecnt = 0; BeginReceive(); } } } if (!HoldSending) { BufferInfo binfo; while (_PendingSendMessages.TryDequeue(out binfo)) { var message = binfo.Buffer; int cnt = binfo.Count; if (_OnSend != null && _OnSend(message, cnt)) { if (_OnSendComplete != null) { _OnSendComplete(message, true); } } else { SendRaw(message, cnt, success => { if (_OnSendComplete != null) { _OnSendComplete(message, success); } }); } } } if (_OnUpdate != null) { _OnUpdate(this); } var waitinterval = _UpdateInterval; var easeratio = _EaseUpdateRatio; if (waitinterval > 0 && easeratio > 0) { var easeinterval = waitinterval * easeratio; if (_LastSendTick + easeinterval <= System.Environment.TickCount) { waitinterval = easeinterval; } } _HaveDataToSend.WaitOne(waitinterval); } } } catch (ThreadAbortException) { Thread.ResetAbort(); } catch (Exception e) { PlatDependant.LogError(e); } finally { _ConnectWorkRunning = false; _ConnectWorkCanceled = false; if (_PreDispose != null) { _PreDispose(this); } if (_Socket != null) { _Socket.Close(); _Socket = null; } // set handlers to null. _OnReceive = null; _OnSend = null; _OnSendComplete = null; _OnUpdate = null; _PreDispose = null; } }
public override bool TryReadBlock() // TODO: BufferedSize < 1 -> actual size... may be we need to peek(n) or get and put back. { if (_BufferedStream == null) { ReadBlock(); return(true); } else { while (true) { if (_Type == 0) { // Determine the start of a message. while (_Tag == 0) { if (BufferedSize < 1) { return(false); } try { _Tag = _CodedInputStream.ReadTag(); } catch (Exception e) { PlatDependant.LogError(e); } } } else { // The Next tag must follow if (_Tag == 0) { if (BufferedSize < 1) { return(false); } try { _Tag = _CodedInputStream.ReadTag(); if (_Tag == 0) { ResetReadBlockContext(); continue; } } catch (Exception e) { PlatDependant.LogError(e); ResetReadBlockContext(); continue; } } } try { int seq = Google.Protobuf.WireFormat.GetTagFieldNumber(_Tag); var ttype = Google.Protobuf.WireFormat.GetTagWireType(_Tag); if (seq == 1 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { if (BufferedSize < 1) { return(false); } ResetReadBlockContext(); _Type = _CodedInputStream.ReadUInt32(); } else if (_Type != 0) { if (seq == 2 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { if (BufferedSize < 1) { return(false); } _Flags = _CodedInputStream.ReadUInt32(); } else if (seq == 3 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { if (BufferedSize < 1) { return(false); } _Seq = _CodedInputStream.ReadUInt32(); } else if (seq == 4 && ttype == Google.Protobuf.WireFormat.WireType.Varint) { if (BufferedSize < 1) { return(false); } _SSeq = _CodedInputStream.ReadUInt32(); } else if (seq == 5 && ttype == Google.Protobuf.WireFormat.WireType.LengthDelimited) { if (!_SizeReady) { if (BufferedSize < 1) { return(false); } _Size = _CodedInputStream.ReadLength(); _SizeReady = true; } if (_Size >= 0) { if (BufferedSize < _Size) { return(false); } if (_Size > CONST.MAX_MESSAGE_LENGTH) { PlatDependant.LogError("We got a too long message. We will drop this message and treat it as an error message."); _CodedInputStream.SkipRawBytes(_Size); FireReceiveBlock(null, 0, _Type, _Flags, _Seq, _SSeq); } else { _ReadBuffer.Clear(); _CodedInputStream.ReadRawBytes(_ReadBuffer, _Size); FireReceiveBlock(_ReadBuffer, _Size, _Type, _Flags, _Seq, _SSeq); } } else { FireReceiveBlock(null, 0, _Type, _Flags, _Seq, _SSeq); } ResetReadBlockContext(); return(true); } } _Tag = 0; } catch (Exception e) { PlatDependant.LogError(e); ResetReadBlockContext(); } } } }
protected virtual void ConnectWork() { try { PrepareSocket(); if (_Socket != null) { byte[] receivebuffer = new byte[CONST.MTU]; int receivecnt = 0; Action BeginReceive = () => { _Socket.BeginReceive(receivebuffer, 0, 1, SocketFlags.None, ar => { try { receivecnt = _Socket.EndReceive(ar); if (receivecnt > 0) { var bytesRemaining = _Socket.Available; if (bytesRemaining > 0) { if (bytesRemaining > CONST.MTU - 1) { bytesRemaining = CONST.MTU - 1; } receivecnt += _Socket.Receive(receivebuffer, 1, bytesRemaining, SocketFlags.None); } } else { if (_ConnectWorkRunning) { _ConnectWorkCanceled = true; } } } catch (Exception e) { if (IsConnectionAlive) { _ConnectWorkCanceled = true; PlatDependant.LogError(e); } } _HaveDataToSend.Set(); }, null); }; BeginReceive(); while (!_ConnectWorkCanceled) { if (receivecnt > 0) { if (_OnReceive != null) { _OnReceive(receivebuffer, receivecnt, _Socket.RemoteEndPoint); } receivecnt = 0; BeginReceive(); } BufferInfo binfo; while (_PendingSendMessages.TryDequeue(out binfo)) { var message = binfo.Buffer; int cnt = binfo.Count; if (_OnSend != null && _OnSend(message, cnt)) { if (_OnSendComplete != null) { _OnSendComplete(message, true); } } else { SendRaw(message, cnt, success => { if (_OnSendComplete != null) { _OnSendComplete(message, success); } }); } } _HaveDataToSend.WaitOne(); } _Socket.Shutdown(SocketShutdown.Both); } } catch (ThreadAbortException) { Thread.ResetAbort(); } catch (Exception e) { PlatDependant.LogError(e); } finally { _ConnectWorkRunning = false; _ConnectWorkCanceled = false; if (_PreDispose != null) { _PreDispose(this); } if (_Socket != null) { _Socket.Close(); _Socket = null; } // set handlers to null. _OnReceive = null; _OnSend = null; _OnSendComplete = null; _PreDispose = null; } }
protected override void ConnectWork() { try { KnownRemotes remotes = null; if (_ListenBroadcast) { IPAddressInfo.Refresh(); _SocketsBroadcast = new List <BroadcastSocketReceiveInfo>(); remotes = new KnownRemotes(); _KnownRemotes = new KnownRemotes(); _KnownRemotesR = new KnownRemotes(); _KnownRemotesS = new KnownRemotes(); } if (_ListenBroadcast) { var ipv4addrs = IPAddressInfo.LocalIPv4Addresses; for (int i = 0; i < ipv4addrs.Length; ++i) { try { var address = ipv4addrs[i]; var socket = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); socket.Bind(new IPEndPoint(address, _Port)); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(IPAddressInfo.IPv4MulticastAddress, address)); socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 5); _SocketsBroadcast.Add(new BroadcastSocketReceiveInfo(this, socket, new IPEndPoint(IPAddress.Any, _Port))); if (_Socket == null) { _Socket = socket; } } catch (Exception e) { PlatDependant.LogError(ipv4addrs[i]); PlatDependant.LogError(e); } } } if (_Socket == null) { var address4 = IPAddress.Any; _Socket = new Socket(address4.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _Socket.Bind(new IPEndPoint(address4, _Port)); } #if NET_STANDARD_2_0 || NET_4_6 // Notice: it is a pitty that unity does not support ipv6 multicast. (Unity 5.6) if (_ListenBroadcast) { var ipv6addrs = IPAddressInfo.LocalIPv6Addresses; for (int i = 0; i < ipv6addrs.Length; ++i) { try { var address = ipv6addrs[i]; var maddr = IPAddressInfo.IPv6MulticastAddressOrganization; if (address.IsIPv6SiteLocal) { maddr = IPAddressInfo.IPv6MulticastAddressSiteLocal; } else if (address.IsIPv6LinkLocal) { maddr = IPAddressInfo.IPv6MulticastAddressLinkLocal; } var socket = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); socket.Bind(new IPEndPoint(address, _Port)); var iindex = IPAddressInfo.GetInterfaceIndex(address); if (iindex == 0) { socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(maddr)); } else { socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.AddMembership, new IPv6MulticastOption(maddr, iindex)); } socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastTimeToLive, 5); _SocketsBroadcast.Add(new BroadcastSocketReceiveInfo(this, socket, new IPEndPoint(IPAddress.IPv6Any, _Port))); if (_Socket6 == null) { _Socket6 = socket; } } catch (Exception e) { PlatDependant.LogError(ipv6addrs[i]); PlatDependant.LogError(e); } } } #endif if (_Socket6 == null) { var address6 = IPAddress.IPv6Any; _Socket6 = new Socket(address6.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _Socket6.Bind(new IPEndPoint(address6, _Port)); } if (_ListenBroadcast) { for (int i = 0; i < _SocketsBroadcast.Count; ++i) { var bsinfo = _SocketsBroadcast[i]; bsinfo.BeginReceive(); } int knownRemotesVersion = 0; while (!_ConnectWorkCanceled) { bool knownRemotesChanged = false; var curTick = Environment.TickCount; for (int i = 0; i < _SocketsBroadcast.Count; ++i) { var bsinfo = _SocketsBroadcast[i]; if (bsinfo.ReceiveCount > 0) { var ep = bsinfo.RemoteEP as IPEndPoint; //var remote = new IPEndPoint(ep.Address, ep.Port); remotes.Remotes[ep.Address] = new KnownRemote() { Address = ep.Address, LocalSocket = bsinfo.LocalSocket, LastTick = curTick }; knownRemotesChanged = true; } } if (remotes.Remotes.Count > 100) { KnownRemote[] aremotes = new KnownRemote[remotes.Remotes.Count]; remotes.Remotes.Values.CopyTo(aremotes, 0); Array.Sort(aremotes, (ra, rb) => ra.LastTick - rb.LastTick); for (int i = 0; i < aremotes.Length - 100; ++i) { var remote = aremotes[i]; if (remote.LastTick + 15000 <= curTick) { remotes.Remotes.Remove(remote.Address); } else { break; } } } // TODO: check dead knownRemotes... if (knownRemotesChanged) { _KnownRemotesR.Remotes.Clear(); foreach (var kvp in remotes.Remotes) { _KnownRemotesR.Remotes[kvp.Key] = kvp.Value; } _KnownRemotesR.Version = ++knownRemotesVersion; _KnownRemotesR = System.Threading.Interlocked.Exchange(ref _KnownRemotes, _KnownRemotesR); } if (_OnReceive != null) { for (int i = 0; i < _SocketsBroadcast.Count; ++i) { var bsinfo = _SocketsBroadcast[i]; if (bsinfo.ReceiveCount > 0) { _OnReceive(bsinfo.ReceiveData, bsinfo.ReceiveCount, bsinfo.RemoteEP); } } } for (int i = 0; i < _SocketsBroadcast.Count; ++i) { var bsinfo = _SocketsBroadcast[i]; if (bsinfo.ReceiveResult.IsCompleted) { bsinfo.BeginReceive(); } } if (_OnUpdate != null) { _OnUpdate(this); } _HaveDataToSend.WaitOne(_UpdateInterval); } } else { EndPoint sender4 = new IPEndPoint(IPAddress.Any, _Port); EndPoint sender6 = new IPEndPoint(IPAddress.IPv6Any, _Port); byte[] data4 = new byte[CONST.MTU]; byte[] data6 = new byte[CONST.MTU]; int dcnt4 = 0; int dcnt6 = 0; IAsyncResult readar4 = null; IAsyncResult readar6 = null; Action BeginReceive4 = () => { readar4 = _Socket.BeginReceiveFrom(data4, 0, CONST.MTU, SocketFlags.None, ref sender4, ar => { try { dcnt4 = _Socket.EndReceiveFrom(ar, ref sender4); } catch (Exception e) { if (IsConnectionAlive) { _ConnectWorkCanceled = true; PlatDependant.LogError(e); } } _HaveDataToSend.Set(); }, null); }; Action BeginReceive6 = () => { readar6 = _Socket6.BeginReceiveFrom(data6, 0, CONST.MTU, SocketFlags.None, ref sender6, ar => { try { dcnt6 = _Socket6.EndReceiveFrom(ar, ref sender6); } catch (Exception e) { if (IsConnectionAlive) { _ConnectWorkCanceled = true; PlatDependant.LogError(e); } } _HaveDataToSend.Set(); }, null); }; BeginReceive4(); BeginReceive6(); while (!_ConnectWorkCanceled) { if (_OnReceive != null) { if (dcnt4 > 0) { _OnReceive(data4, dcnt4, sender4); dcnt4 = 0; } if (dcnt6 > 0) { _OnReceive(data6, dcnt6, sender6); dcnt6 = 0; } } if (readar4.IsCompleted) { BeginReceive4(); } if (readar6.IsCompleted) { BeginReceive6(); } if (_OnUpdate != null) { _OnUpdate(this); } _HaveDataToSend.WaitOne(_UpdateInterval); } } } catch (ThreadAbortException) { Thread.ResetAbort(); } catch (Exception e) { PlatDependant.LogError(e); } finally { _ConnectWorkRunning = false; _ConnectWorkCanceled = false; if (_PreDispose != null) { _PreDispose(this); } if (_Socket != null) { _Socket.Close(); _Socket = null; } if (_Socket6 != null) { _Socket6.Close(); _Socket6 = null; } if (_SocketsBroadcast != null) { for (int i = 0; i < _SocketsBroadcast.Count; ++i) { var bsinfo = _SocketsBroadcast[i]; if (bsinfo != null && bsinfo.LocalSocket != null) { bsinfo.LocalSocket.Close(); } } _SocketsBroadcast = null; } // set handlers to null. _OnReceive = null; _OnSend = null; _OnSendComplete = null; _OnUpdate = null; _PreDispose = null; } }