/* Sog 游戏基础库 2016 by zouwei */ using System; using System.Net; using System.Net.Sockets; using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; namespace SogClient { public class TcpClientSession : ClientSession { protected ConnectedClientSessionUpdate m_sessionUpdate; public TcpClientSession(ClientSessionSettings clientSettings, ConnectedClientSessionUpdate updateMgr, SessionNetSelectMode mode) :base(clientSettings) { AllockSocket(); m_sessionUpdate = updateMgr; NetSessionObj = new TcpSession(m_socketClient); } private void AllockSocket() { m_socketClient = new Socket(m_clientSettings.RemoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); m_socketClient.Blocking = false; m_socketClient.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1); } public override void Connect() { TraceLog.Trace("TcpClientSession.Connect from local {1} to remote {0} sessionID:{2}", m_clientSettings.RemoteEndPoint, NetSessionObj.LocalEndPoint, NetSessionObj.SessionID); m_isConnected = false; m_isConnecting = true; bool connFail = false; try { m_socketClient.Connect(m_clientSettings.RemoteEndPoint); } catch (ObjectDisposedException ex) { TraceLog.Error("TcpClientSession.Connect {0} ObjectDisposedException message {1}", m_clientSettings.RemoteEndPoint, ex.Message); connFail = true; } catch (InvalidOperationException ex) { TraceLog.Error("TcpClientSession.Connect {0} InvalidOperationException message {1}", m_clientSettings.RemoteEndPoint, ex.Message); connFail = true; } catch (SocketException ex) { // 返回 WouldBlock 是正常的,微软官方解释: An operation on a nonblocking socket cannot be completed immediately. // 但是返回其他异常呢? TraceLog.Trace("TcpClientSession.Connect {0}, wait connected finish SocketErrorCode {1},", m_clientSettings.RemoteEndPoint, ex.SocketErrorCode); } catch (Exception ex) { TraceLog.Error("TcpClientSession.Connect {0} fail, exception {1}" , m_clientSettings.RemoteEndPoint, ex); connFail = true; } if (connFail) { TraceLog.Error("TcpClientSession.Connect connFail is True! "); TcpConnectFail(); } } public override void Reconnect() { TraceLog.Trace("TcpClientSession.Reconnect from local {1} to remote {0} sessionID:{2}", m_clientSettings.RemoteEndPoint, NetSessionObj.LocalEndPoint, NetSessionObj.SessionID); // 重连时m_socketClient如果不是null,要丢掉session中未发送和未解析的信息 if (m_socketClient != null) { TraceLog.Error("TcpClientSession.Reconnect close old socket"); CloseSession(); } //重连的时候重新allock socket,linux下必须如此 AllockSocket(); Connect(); } private void TcpConnectFail() { TraceLog.Trace("TcpClientSession : TcpConnectFail"); CloseSession(); SessionEventArgs arg = new SessionEventArgs(); arg.Session = NetSessionObj; OnConnectFail(arg); } public override void Update(long nowMs) { UpdateConnect(); UpdateReadWrite(); } public void UpdateConnect() { if (!m_isConnecting) { return; } bool bError = m_socketClient.Poll(0, SelectMode.SelectError); if (bError) { TraceLog.Trace("TcpClientSession.UpdateConnect bError is True! sessionId:{0}", NetSessionObj.SessionID); TcpConnectFail(); } else { bool bWrite = m_socketClient.Poll(0, SelectMode.SelectWrite); if(bWrite) { ConnectSucc(); } } } protected void UpdateReadWrite() { if (m_socketClient == null) { return; } if (m_isConnected) { if (NetSessionObj.IsSocketClosed) { OnUpdateConnectedSocketError(); return; } m_sessionUpdate.AddToList(this); } } protected override void CloseSession() { TraceLog.Trace("TcpClientSession.CloseSession session {0}" , NetSessionObj.SessionID); m_isConnected = false; m_isConnecting = false; //丢弃正在发送和接收的数据,关闭socket NetSessionObj.Close(); m_socketClient = null; } } }