关于使用IOCP创建服务端的问题

warcraftmgq 2018-03-28 03:56:46
这个是服务代码

using IOCP.Protocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace IOCP.Base
{
public class AppServer
{
public event SessionConnectedHandler OnSessionConnected;
public event SessionLostConnectHandler OnSessonLostConnect;
public event SessionMessageArrived OnSessionMessageArrived;

private ReceiveFilter filter;
private RequestSerializer serializer;

private ServerConfig config;
private BufferManager bufferManager;
private SAEAPool seaPool;
private MemoryPool memoryPool;
private Socket _listener;
private System.Timers.Timer tmrTimeout;

private Dictionary<string, SocketAsyncEventArgs> clients;

public AppServer(ReceiveFilter filter, RequestSerializer serializer)
{
this.filter = filter;
this.serializer = serializer;
}

public void Start(ServerConfig config)
{
if (_listener != null)
{
return;
}
this.config = config;
filter.Charset = config.Charset;
Init();
StartListen();
}

public void Stop()
{
try
{
_listener.Close();
tmrTimeout.Stop();
lock (this)
{
foreach (var kp in clients)
{
CloseSocket(kp.Value, CloseReason.ServerShutdown);
}
}
}
catch (Exception ex)
{

}
}

private void Init()
{
clients = new Dictionary<string, SocketAsyncEventArgs>();
bufferManager = new BufferManager(config.MaxConnectionNumber * config.ReceiveBufferSize, config.ReceiveBufferSize);
memoryPool = new MemoryPool(config.MaxConnectionNumber, config.ClientBufferSize);
seaPool = new SAEAPool(config.MaxConnectionNumber);

SocketAsyncEventArgs readWriteEventArg;
for (int i = 0; i < config.MaxConnectionNumber; i++)
{
readWriteEventArg = new SocketAsyncEventArgs();
readWriteEventArg.Completed += IOCompleted;
bufferManager.SetBuffer(readWriteEventArg);
seaPool.Push(readWriteEventArg);
}
}

private void StartListen()
{
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(new IPEndPoint(IPAddress.Any, config.Port));
_listener.Listen(config.ListenBlockNumber);
StartAccept(null);

tmrTimeout = new System.Timers.Timer();
tmrTimeout.Elapsed += tmrTimeout_Elapsed;
tmrTimeout.Interval = config.TimeoutCheckInterval * 1000;
tmrTimeout.Start();
}

private void tmrTimeout_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
List<SocketAsyncEventArgs> ls = new List<SocketAsyncEventArgs>();
lock (this)
{
foreach (var kp in clients)
{
AppSession session = kp.Value.UserToken as AppSession;
if ((DateTime.Now - session.SocketSession.LastResponseTime).TotalSeconds > config.ClientTimeout)
{
ls.Add(kp.Value);
}
}
foreach (var c in ls)
{
string addressId = ((AppSession)c.UserToken).SocketSession.S.RemoteEndPoint.ToString();
try
{
CloseSocket(c, CloseReason.Timeout);
}
catch (Exception ex)
{

}
finally
{
clients.Remove(addressId);
}
}

}
}

private void StartAccept(SocketAsyncEventArgs e)
{
try
{
if (e == null)
{
e = new SocketAsyncEventArgs();
e.Completed += AcceptCompleted;
}
else
{
e.AcceptSocket = null;
}
if (!_listener.AcceptAsync(e))
{
ProcessAccept(e);
}
}
catch (Exception ex)
{
}
}

private void AcceptCompleted(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
}

private void IOCompleted(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
ProcessSend(e);
break;
}
}

private void ProcessAccept(SocketAsyncEventArgs e)
{
Socket s = e.AcceptSocket;
if (s != null && s.Connected)
{
SocketAsyncEventArgs reader = seaPool.Pop();
if (reader == null)
{
s.Close();
}
else
{
try
{
ClientBuffer cb = new ClientBuffer(memoryPool.Pop());
SocketSession ss = new SocketSession(s, cb);
AppSession token = new AppSession(ss, config.Charset);
token.Serializer = serializer;
reader.UserToken = token;
lock (this)
{
clients.Add(s.RemoteEndPoint.ToString(), e);
}

if (OnSessionConnected != null)
{
OnSessionConnected(token);
}

if (!s.ReceiveAsync(reader))
{
ProcessReceive(e);
}
}
catch (SocketException ex)
{
seaPool.Push(reader);
}
}
}
StartAccept(e);
}

private void ProcessReceive(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
if (e.BytesTransferred > 0)
{
AppSession token = e.UserToken as AppSession;
token.SocketSession.Buffer.Write(e.Buffer, e.Offset, e.BytesTransferred);

//尝试解析缓冲区内容
int offset = 0;
int rest = 0;
RequestInfo req = null;
while ((req = filter.ResolveRequestInfo(token.SocketSession.Buffer.Body, offset, token.SocketSession.Buffer.Length, out rest)) != null)
{
//处理请求
if (OnSessionMessageArrived != null)
{
OnSessionMessageArrived(token, req);
}
offset += rest;
}
token.SocketSession.Buffer.Read(offset);
if (!token.SocketSession.S.ReceiveAsync(e))
{
ProcessReceive(e);
}
}
else
{
CloseSocket(e, CloseReason.ClientClose);
}
}
else
{
CloseSocket(e, CloseReason.SocketError);
}
}

private void ProcessSend(SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
//todo
}
else
{
CloseSocket(e, CloseReason.SocketError);
}
}

private void CloseSocket(SocketAsyncEventArgs e, CloseReason closeReason)
{
AppSession token = e.UserToken as AppSession;
try
{
token.SocketSession.S.Shutdown(SocketShutdown.Both);
RaiseDisconnectEvent(e, closeReason);
}
catch (Exception ex)
{

}
finally
{
token.SocketSession.S.Close();
}
memoryPool.Push(token.SocketSession.Buffer.Body);
seaPool.Push(e);
e.UserToken = null;
}


这个是调用代码

AppServer host = new AppServer(new ReceiveFilter(5), new RequestSerializer(5));
host.Start(new ServerConfig()
{
Port = 13001,
MaxConnectionNumber = 3000,
ListenBlockNumber = 100,
ReceiveBufferSize = 1024,
ClientBufferSize = 4096,
ClientTimeout = 30,
TimeoutCheckInterval = 10
});

host.OnSessionConnected += host_OnSessionConnected;
host.OnSessionMessageArrived += host_OnSessionMessageArrived;
host.OnSessonLostConnect += host_OnSessonLostConnect;

Console.WriteLine("服务器已启动");


现在的问题是将服务程序放在内网的测试服务器可以轻松建立1000个长连接,而且不间断发数据包且相应,但是放在公网的服务器上大约创建了400来个就很慢了,而且经常出现服务无响应的错误。这个是因为服务代码逻辑导致的还是有可能是服务器系统设置导致的?系统是Windows Server 2008 R2企业版。
...全文
240 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
warcraftmgq 2018-03-28
  • 打赏
  • 举报
回复
其它的一些辅助类没有贴代码,都是从MSDN上抄的。

110,556

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧