C# 实现的多线程异步Socket数据包接收器框架(2)
来源:互联网 发布:linux软件 编辑:程序博客网 时间:2024/04/28 04:08
下面是创建侦听Socket对象的方法代码。
Code
/// <summary>
/// 创建接收服务器的 Socket, 并侦听客户端连接请求
/// </summary>
private bool CreateReceiverSocket()
{
try
{
_receiverSocket =new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_receiverSocket.Bind(new IPEndPoint(IPAddress.Any, _tcpSocketPort));// 绑定端口
_receiverSocket.Listen(_maxAllowListenQueueLength);// 开始监听
return true;
}
catch
{
this.OnReceiverException();
return false;
}
}
/// <summary>
/// 创建接收服务器的 Socket, 并侦听客户端连接请求
/// </summary>
private bool CreateReceiverSocket()
{
try
{
_receiverSocket =new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_receiverSocket.Bind(new IPEndPoint(IPAddress.Any, _tcpSocketPort));// 绑定端口
_receiverSocket.Listen(_maxAllowListenQueueLength);// 开始监听
return true;
}
catch
{
this.OnReceiverException();
return false;
}
}
3.2 侦听客户端连接请求
服务器端循环等待客户端连接请求。一旦有请求,先判断客户端连接数是否超限,接着检测该客户端IP地址,一切正常后建立TSession对象,并调用异步方法接收客户端Socket数据包。
代码中,Socket读到数据时的回调AsyncCallback委托方法EndReceiveData()完成数据接收工作,正常情况下启动另一个异步BeginReceive()调用。
.NET中,每个异步方法都有自己的独立线程,异步处理其实也基于多线程机制的。下面代码中的异步套异步调用,既占用较大的系统资源,也给处理带来意想不到的结果,更是出现异常时难以控制和处理的关键所在。
Code
/// <summary>
/// 循环侦听客户端请求,由于要用线程池,故带一个参数
/// </summary>
private void ListenClientRequest(object state)
{
Socket client =null;
while (!_stopReceiver)
{
if (_stopConnectRequest)// 停止客户端连接请求
{
if (_receiverSocket!=null)
{
try
{
_receiverSocket.Close(); // 强制关闭接收器
}
catch
{
this.OnReceiverException();
}
finally
{
// 必须为 null,否则 disposed 对象仍然存在,将引发下面的错误
_receiverSocket =null;
}
}
continue;
}
else
{
if (_receiverSocket==null)
{
if (!this.CreateReceiverSocket())
{
continue;
}
}
}
try
{
if (_receiverSocket.Poll(_loopWaitTime, SelectMode.SelectRead))
{
// 频繁关闭、启动时,这里容易产生错误(提示套接字只能有一个)
client = _receiverSocket.Accept();
if (client != null&& client.Connected)
{
if (this._clientCount>=this._maxAllowClientCount)
{
this.OnReceiverException();
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
else if (CheckSameClientIP(client))// 已存在该 IP 地址
{
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
else
{
TSession session =new TSession(client);
session.LoginTime = DateTime.Now;
lock (_sessionTable)
{
int preSessionID= session.ID;
while (true)
{
if (_sessionTable.ContainsKey(session.ID))// 有可能重复该编号
{
session.ID =100000+ preSessionID;
}
else
{
break;
}
}
_sessionTable.Add(session.ID, session); // 登记该会话客户端
Interlocked.Increment(ref _clientCount);
}
this.OnClientRequest();
try // 客户端连续连接或连接后立即断开,易在该处产生错误,系统忽略之
{
// 开始接受来自该客户端的数据
session.ClientSocket.BeginReceive(session.ReceiveBuffer,0,
session.ReceiveBufferLength, SocketFlags.None, EndReceiveData, session);
}
catch
{
session.DisconnectType = TDisconnectType.Exception;
session.State = TSessionState.NoReply;
}
}
}
else if (client != null)// 非空,但没有连接(connected is false)
{
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
}
}
catch
{
this.OnReceiverException();
if (client != null)
{
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
}
// 该处可以适当暂停若干毫秒
}
// 该处可以适当暂停若干毫秒
}
/// <summary>
/// 循环侦听客户端请求,由于要用线程池,故带一个参数
/// </summary>
private void ListenClientRequest(object state)
{
Socket client =null;
while (!_stopReceiver)
{
if (_stopConnectRequest)// 停止客户端连接请求
{
if (_receiverSocket!=null)
{
try
{
_receiverSocket.Close(); // 强制关闭接收器
}
catch
{
this.OnReceiverException();
}
finally
{
// 必须为 null,否则 disposed 对象仍然存在,将引发下面的错误
_receiverSocket =null;
}
}
continue;
}
else
{
if (_receiverSocket==null)
{
if (!this.CreateReceiverSocket())
{
continue;
}
}
}
try
{
if (_receiverSocket.Poll(_loopWaitTime, SelectMode.SelectRead))
{
// 频繁关闭、启动时,这里容易产生错误(提示套接字只能有一个)
client = _receiverSocket.Accept();
if (client != null&& client.Connected)
{
if (this._clientCount>=this._maxAllowClientCount)
{
this.OnReceiverException();
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
else if (CheckSameClientIP(client))// 已存在该 IP 地址
{
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
else
{
TSession session =new TSession(client);
session.LoginTime = DateTime.Now;
lock (_sessionTable)
{
int preSessionID= session.ID;
while (true)
{
if (_sessionTable.ContainsKey(session.ID))// 有可能重复该编号
{
session.ID =100000+ preSessionID;
}
else
{
break;
}
}
_sessionTable.Add(session.ID, session); // 登记该会话客户端
Interlocked.Increment(ref _clientCount);
}
this.OnClientRequest();
try // 客户端连续连接或连接后立即断开,易在该处产生错误,系统忽略之
{
// 开始接受来自该客户端的数据
session.ClientSocket.BeginReceive(session.ReceiveBuffer,0,
session.ReceiveBufferLength, SocketFlags.None, EndReceiveData, session);
}
catch
{
session.DisconnectType = TDisconnectType.Exception;
session.State = TSessionState.NoReply;
}
}
}
else if (client != null)// 非空,但没有连接(connected is false)
{
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
}
}
catch
{
this.OnReceiverException();
if (client != null)
{
try
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch { }
}
}
// 该处可以适当暂停若干毫秒
}
// 该处可以适当暂停若干毫秒
}
- C# 实现的多线程异步Socket数据包接收器框架(2)
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收器框架 (转)
- C# 实现的多线程异步Socket数据包接收器框架 (转)
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收器框架(1)
- C# 实现的多线程异步Socket数据包接收器框架(3)
- C# 实现的多线程异步Socket数据包接收器框架(4)
- C# 实现的多线程异步Socket数据包接收器框架
- C# 实现的多线程异步Socket数据包接收qi框架
- C# 实现的多线程异步Socket数据包接收器框架(来源http://www.cnblogs.com/wcfgroup/archive/2008/10/06/1304512.html)
- 异步Socket通信编程的C#实现(2)
- C# 多线程同步与异步的实现
- C# Socket TCP 协议接收器
- poj 1364 King
- 2012-08-30 下午随想
- Architects Must Be Hands On written by John Davie
- (3) ActiveMQ -- Cluster
- linux下gcc默认搜索头文件及库文件的路径
- C# 实现的多线程异步Socket数据包接收器框架(2)
- 深入理解Zend SAPIs(Zend SAPI Internals)
- C语言代码优化规范及常见错误举例
- 使用用例捕获需求
- zh-cn en-uk表示语言(文化)代码与国家地区对照表
- 上网如何赚钱
- 11g R2 RAC 环境下开启归档模式的方法
- IBOutlet和IBAction
- Android中Context详解 ---- 你所不知道的Context