123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- using System;
- using System.Net.Sockets;
- using System.Threading.Tasks;
- namespace XGame.Framework.Network
- {
- public class TCPSession : IRemoteSession, IDisposable
- {
- readonly int TIMEOUT = 4000;
- private IAsyncResult _asyncResultRead;
- private IAsyncResult _asyncResultWrite;
- private Socket _socket;
- private NetworkStream _tcpStream;
- private byte[] _buffers;
- private volatile SessionStatus _status = SessionStatus.FREE;
- public SessionStatus Status => _status;
- public SessionAddress Address { get; private set; }
- private ISessionContext _context;
- internal TCPSession(int bufferSize, int timeout, ISessionContext context)
- {
- _buffers = new byte[bufferSize];
- TIMEOUT = timeout;
- _context = context;
- }
- #region Connect Method
- private void OnDnsCompleted(SessionAddress address)
- {
- if (string.IsNullOrEmpty(address.IP))
- {
- OnConnectFail(new Exception("[Session] 域名解析失败或IP为空"));
- return;
- }
- Task.Factory.StartNew(() =>
- {
- try
- {
- _socket = new Socket(address.IsIpv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
- IAsyncResult connectAsync = _socket.BeginConnect(address.IP, address.PORT, null, _socket);
- _status = SessionStatus.CONNECTING;
- bool success = connectAsync.AsyncWaitHandle.WaitOne(TIMEOUT, true);
- if (success && _socket.Connected)
- {
- _socket.EndConnect(connectAsync);
- _tcpStream = new NetworkStream(_socket);
- _socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true); //设置无延迟发送
- OnConnected();
- }
- else
- {
- OnConnectTimeout();
- }
- }
- catch (Exception e)
- {
- OnConnectFail(e);
- }
- });
- }
- public void Connect(AddressInfo info)
- {
- if (Status != SessionStatus.FREE)
- {
- Log.Warn($"[Session]SessionStatus:{Status} 已连接或者正在连接,又尝试连接");
- return;
- }
- OnStartConnect();
- if (Address != null && Address.Domain == info.Address && Address.PORT == info.Port)
- {
- OnDnsCompleted(Address);
- }
- else
- {
- Address = new SessionAddress(info);
- Address.ParseDnsAsync(OnDnsCompleted);
- }
- }
- public bool IsConnected(bool bPrecise)
- {
- if (null != _socket)
- {
- if (Status == SessionStatus.CONNECTED && _socket.Connected)
- {
- if (!bPrecise)
- {
- return true;
- }
- try
- {
- return !(_socket.Poll(1000, SelectMode.SelectRead) && _socket.Available == 0);
- }
- catch (SocketException e)
- {
- Log.Warn($"[Session]Error:SocketException --socket poll error: {e.Message} errorcode:{e.SocketErrorCode}");
- return false;
- }
- catch (Exception e)
- {
- Log.Warn("[Session]Error:Exception --socket poll error: {0}", e.Message);
- return false;
- }
- }
- }
- return false;
- }
- private void OnConnectFail(Exception e)
- {
- _status = SessionStatus.CONNECT_FAIL;
- _context.Synchronizer.Enqueue(ESessionCode.ConnectFail, e);
- }
- private void OnConnectTimeout()
- {
- _status = SessionStatus.CONNECT_TIMEOUT;
- _context.Synchronizer.Enqueue(ESessionCode.ConnectTimeout, null);
- }
- private void OnConnected()
- {
- _status = SessionStatus.CONNECTED;
- _context.Synchronizer.Enqueue(ESessionCode.Connected, null);
- StartReceive();
- }
- private void OnStartConnect()
- {
- _context.Synchronizer.Enqueue(ESessionCode.StartConnect, null);
- }
- #endregion
- #region Disconnect Method
- public void Disconnect()
- {
- if (Status != SessionStatus.FREE)
- {
- try
- {
- if (_asyncResultRead != null && !_asyncResultRead.IsCompleted)
- {
- _asyncResultRead.AsyncWaitHandle.Close();
- _socket.Shutdown(SocketShutdown.Receive);
- }
- if (_asyncResultWrite != null && !_asyncResultWrite.IsCompleted)
- {
- _asyncResultWrite.AsyncWaitHandle.Close();
- _socket.Shutdown(SocketShutdown.Send);
- }
- if (_tcpStream != null)
- {
- _tcpStream.Close();
- _tcpStream.Dispose();
- }
- _socket.Close();
- _socket.Dispose();
- }
- catch (Exception e)
- {
- OnDisconnectError(e);
- }
- _status = SessionStatus.FREE;
- OnDisconnect();
- }
- }
- private void OnDisconnect()
- {
- _context.Synchronizer.Enqueue(ESessionCode.Disconnect, null);
- }
- private void OnDisconnectError(Exception e)
- {
- _context.Synchronizer.Enqueue(ESessionCode.DisconnectError, e);
- }
- #endregion
- #region Send Method
- public bool Send(byte[] bytes, int offset, int length)
- {
- try
- {
- _asyncResultWrite = _tcpStream.BeginWrite(bytes, offset, length, EndSend, bytes);
- return true;
- }
- catch (Exception e)
- {
- SessionBufferPool.Recycle(bytes);
- OnSendError(e);
- }
- return false;
- }
- private void EndSend(IAsyncResult ar)
- {
- try
- {
- _tcpStream.EndWrite(ar);
- }
- catch (Exception e)
- {
- OnSendError(e);
- }
- finally
- {
- var buffer = ar.AsyncState as byte[];
- SessionBufferPool.Recycle(buffer);
- }
- }
- private void OnSendError(Exception e)
- {
- _status = SessionStatus.SEND_ERROR;
- _context.Synchronizer.Enqueue(ESessionCode.SendException, e);
- }
- #endregion
- #region Receive Method
- public void StartReceive()
- {
- try
- {
- _asyncResultRead = _tcpStream.BeginRead(_buffers, 0, _buffers.Length, EndReceive, _socket);
- }
- catch (Exception e)
- {
- OnReceiveError(e);
- }
- }
- private void EndReceive(IAsyncResult asyncReceive)
- {
- try
- {
- int length = _tcpStream.EndRead(asyncReceive);
- if (length > 0)
- {
- OnRead(_buffers, 0, length);//处理
- StartReceive();
- }
- else
- {
- OnRemoteClose();
- }
- }
- catch (Exception e)
- {
- OnReceiveError(e);
- }
- }
- private void OnReceiveError(Exception e)
- {
- _status = SessionStatus.RECV_ERROR;
- _context.Synchronizer.Enqueue(ESessionCode.RecvError, e);
- }
- private void OnRead(byte[] bytes, int offset, int length)
- {
- var buffer = SessionBufferPool.Acquire();
- Array.Copy(bytes, offset, buffer, 0, length);
- _context.Synchronizer.Enqueue(buffer, 0, length);
- }
- private void OnRemoteClose()
- {
- _status = SessionStatus.CLOSED;
- _context.Synchronizer.Enqueue(ESessionCode.SessionClose, null);
- }
- #endregion
- void IDisposable.Dispose()
- {
- Disconnect();
- _context = null;
- }
- }
- }
|