📄 smgsocketpool.cs
字号:
/* jll(2005)版权所有,保留所有权力
* 文件名:SMGSocketPool.cs
* 用 途:这个文件包含一个SMGSocketPool的类,这个类建立socket缓冲池负责将二级sp发送的命令转发到服务器,
* 又将服务器的应答转发到二级sp
* 作 者:jll
* 完成日期:2005年8月2日
* 修订记录:
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace JLL.SGIP
{
public class SMGSocketPool
{
private List<Socket> _buffer;
private List<Socket> _using;
private int _lessSocketCount = 0; //缺少的socket的个数, 如果缺少的socket到达某一数量,则应该考虑重新申请socket
private IPAddress _serverIP;
private int _serverPort;
private int _maxSocketConnection;
private string _userName;
private string _passWord;
internal int _answerTimeOut; //命令应答的最大间隔,毫秒
internal SMGSocketPool()
{
_serverIP = SgipConfig.Server.IP;
_serverPort = SgipConfig.Server.Port;
_maxSocketConnection = SgipConfig.Server.MaxConnection;
_userName = SgipConfig.SP.UserName;
_passWord = SgipConfig.SP.Password;
_answerTimeOut = SgipConfig.System.AnswerTimeOut * 1000;
_buffer = new List<Socket>(_maxSocketConnection);
_using = new List<Socket>(_maxSocketConnection);
new System.Threading.Timer(new System.Threading.TimerCallback(CreateSocketPool), null, 0, 65000);
}
/// <summary>
/// 向服务器发起一个连接,如果成功就将该Socket放入缓冲池中
/// </summary>
private void CreateASocket(object state)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
s.Connect(_serverIP, _serverPort);
//向服务器(联通smg)发送bind命令,登录
Bind bindBody = new Bind();
bindBody.LoginName = _userName;
bindBody.LoginPassword = _passWord;
bindBody.LoginType = 1;
Command cmd = Command.CreateCommand(bindBody);
s.Send(cmd.GetBytes());
//接收应答
byte[] buff = new byte[1024];
s.ReceiveTimeout = _answerTimeOut;
s.Receive(buff);
cmd = Command.ToCommand(buff, 0);
if (((Bind_Resp)cmd.Body).Result == 0)
{
//已向服务器建立起了一个连接, 放于缓冲池中
lock (_buffer)
{
_buffer.Add(s);
}
}
}
catch
{
SgipHelper.ShutdownAndCloseSocket(s);
}
}
/// <summary>
/// 如果socket被关闭了, 就从缓冲池中移除,并返回true, 否则返回false
/// </summary>
/// <param name="s"></param>
private bool RemoveIfDisconnected(Socket s)
{
if (!SgipHelper.IsSocketConnected(s))
{
SgipHelper.ShutdownAndCloseSocket(s);
lock (_buffer)
{
_buffer.Remove(s);
}
return true;
}
return false;
}
/// <summary>
/// 建立起尽量多的socket连接放至缓冲池中
/// </summary>
private void PoolBufferSocket()
{
int nCount = _maxSocketConnection - _buffer.Count - _using.Count;
for (int i = 0; i < nCount; ++i)
{
CreateASocket(null);
}
}
/// <summary>
/// 检查缓冲池中每一个socket的连接状态,如果断开了,则从缓冲池中移除
/// </summary>
private void CheckBufferSocket()
{
lock (_buffer)
{
int nCount = _buffer.Count;
for (int i = 0; i < nCount; ++i)
{
RemoveIfDisconnected(_buffer[i]);
}
}
}
/// <summary>
/// 定期检查缓冲池中的socket是否有效,无效则移除并向服务器建立尽可能多的连接
/// </summary>
/// <param name="state"></param>
private void CreateSocketPool(object state)
{
CheckBufferSocket();
PoolBufferSocket();
}
/// <summary>
/// 回收一个socket到缓冲池中
/// </summary>
/// <param name="s"></param>
public void CollectSocket(Socket s)
{
lock (this)
{
_using.Remove(s);
_buffer.Add(s);
}
if (RemoveIfDisconnected(s))
{
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(CreateASocket));
}
}
/// <summary>
/// 从池中返回一个socket, 如果池中没有可用的socket, 则返回null
/// </summary>
/// <returns></returns>
public Socket ReuqestSocket()
{
Socket result = null;
lock (this)
{
if (_buffer.Count > 0)
{
_lessSocketCount = 0;
result = _buffer[0];
_buffer.Remove(result);
_using.Add(result);
}
else
{
_lessSocketCount++;
}
//重构缓冲池
if ((_lessSocketCount >= _maxSocketConnection) || (_buffer.Count + _using.Count == 0))
{
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(CreateSocketPool));
}
}
if (result == null)
{
return null;
}
//如果连接中断
if (!SgipHelper.IsSocketConnected(result))
{
CollectSocket(result);
lock (_buffer)
{
return (_buffer.Count > 0) ? ReuqestSocket() : null;
}
}
//清空socket的接收缓冲区
try
{
int nAvailable = result.Available;
if (nAvailable > 0)
{
byte[] buffer = new byte[nAvailable];
result.Receive(buffer);
}
}
catch
{
}
return result;
}
private static SMGSocketPool _smgSocketPool = null;
/// <summary>
/// 建立起联通smg的socket缓冲池, 必须先调用这个方法才能用 ClientSendSubmit()和 ClientSendTrace()
/// </summary>
public static void BuildSocketPool()
{
if (_smgSocketPool == null)
{
_smgSocketPool = new SMGSocketPool();
}
}
/// <summary>
/// 二级sp发送一个Submit命令到联通smg
/// </summary>
/// <param name="client"></param>
/// <param name="cmd"></param>
public static void ClientSendSubmit(Socket client, Command submitCommand)
{
Socket socketSMG = _smgSocketPool.ReuqestSocket();
if (socketSMG == null)
{
return;
}
try
{
//将submit的一些sp设置设为本机信息
Submit body = (Submit)submitCommand.Body;
body.CorpID = SgipConfig.SP.CorpID;
//body.SPNumber = SgipConfig.SP.SPNumber;
socketSMG.Send(submitCommand.GetBytes());
socketSMG.ReceiveTimeout = _smgSocketPool._answerTimeOut;
byte[] buffer = new byte[SgipConfig.MaxBufferCount];
int nRead = socketSMG.Receive(buffer);
//
//这里做一些命令发送成功之后的处理,如:记录到数据库
//
client.Send(buffer, 0, nRead, SocketFlags.None);
}
catch
{
}
finally
{
_smgSocketPool.CollectSocket(socketSMG);
}
}
/// <summary>
/// 二级sp发送一个Trace命令到联通smg
/// </summary>
/// <param name="client"></param>
/// <param name="traceCommand"></param>
public static void ClientSendTrace(Socket client, Command traceCommand)
{
Socket socketSMG = _smgSocketPool.ReuqestSocket();
if (socketSMG == null)
{
return;
}
try
{
socketSMG.Send(traceCommand.GetBytes());
socketSMG.ReceiveTimeout = 300000;//Trace应答最多5分钟
byte[] buffer = new byte[SgipConfig.MaxBufferCount];
socketSMG.Receive(buffer);
Command cmdAnswer = Command.ToCommand(buffer, 0);
client.Send(cmdAnswer.GetBytes());
}
catch
{
}
finally
{
_smgSocketPool.CollectSocket(socketSMG);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -