You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

180 lines
5.4 KiB

/*
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;
}
}
}