使用SocketAsyncEventArgs开发TCP服务器,它是Windows服务的异步方法.我在Main的开头有这两行代码:
ThreadPool.SetMaxThreads(15000, 30000);
ThreadPool.SetMinThreads(10000, 20000);
Run Code Online (Sandbox Code Playgroud)
并且都返回true(记录返回值).现在2000到3000个客户端开始向此服务器发送消息,它开始接受连接(我计算连接数,它是预期的 - 有一个连接池).服务器进程的线程数将增长到~2050到~3050.到现在为止还挺好!
现在有一个Received方法,在ReceiveAsync返回true或SocketAsyncEventArgs的Completed事件后调用.
问题就此开始了:无论客户端连接多少以及发送的消息数量多少,接收的消息最多只能在一秒钟内调用20次!随着客户数量的增加,这个数字(20)下降到~10.
环境:TCP服务器和客户端正在同一台计算机上进行模拟.我在两台机器上测试了代码,一台有2核CPU和4GB RAM,另一台有8核CPU和12GB RAM.(还没有)数据丢失,有时我在每次接收操作中都会收到多条消息.没关系.但是如何才能增加接收操作的数量?
关于实现的附加说明:代码很大,包含许多不同的逻辑.总体描述如下:我有一个SocketAsyncEventArgs用于接受新连接.它很棒.现在,对于每个新接受的连接,我创建一个新的SocketAsyncEventArgs来接收数据.我把这个(为接收创建的SocketAsyncEventArgs)放在一个池中.它不会被重用,但它的UserToken被用于跟踪连接; 例如那些断开连接的连接或那些7分钟内没有发送任何数据的连接将被关闭和处理(SocketAsyncEventArgs的AcceptSocket将被关闭(两者),关闭和处理,SocketAsyncEventArgs对象本身也是如此).这是一个执行这些任务的Sudo类,但所有其他逻辑和日志记录以及错误检查和其他任何内容都被删除,以使其简单明了(也许更容易发现有问题的代码):
class Sudo
{
Socket _listener;
int _port = 8797;
public Sudo()
{
var ipEndPoint = new IPEndPoint(IPAddress.Any, _port);
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(ipEndPoint);
_listener.Listen(100);
Accept(null);
}
void Accept(SocketAsyncEventArgs acceptEventArg)
{
if (acceptEventArg == null)
{
acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += AcceptCompleted;
}
else acceptEventArg.AcceptSocket = null;
bool willRaiseEvent = _listener.AcceptAsync(acceptEventArg); ;
if (!willRaiseEvent) Accepted(acceptEventArg);
}
void AcceptCompleted(object sender, SocketAsyncEventArgs e)
{
Accepted(e); …Run Code Online (Sandbox Code Playgroud) 我试图理解C#中的'SocketAsyncEventArgs'类.http://msdn.microsoft.com/en-us/library/system.net.sockets.socketasynceventargs.aspx
我正在关注本教程:http: //www.codeproject.com/Articles/83102/C-SocketAsyncEventArgs-High-Performance-Socket-Cod
现在我陷入了我应该如何处理我的服务器数据的问题.我想要做的是使用SocketAsyncEventArgs为BufferManager中分配的512字节缓冲区空间的连接客户端.那么我想要做的是将byte []数据解码为我自己的自定义类(ClientPacket),该类保存用于解码和读取的byte [].
这一切都很好,但我的服务器并不总是回答数据问题是:
我是否使用1个SocketAsyncEventArgs进行接收并循环处理接收数据,然后在需要发送时从池中分配SocketAsyncEventArgs然后在完成时返回它?
SocketAsyncEventArgs在读取完成时如何知道?(当它在用新数据覆盖它之前完成了byte []缓冲区),如果我没有回复,它如何在完成后返回池中?
我可以使用SetBuffer和SocketAsyncEventArgs就好了.
如果我尝试使用BufferList(在执行SetBuffer(null,0,0)之后),当我在套接字上执行SendAsync时,我总是立即得到SocketError InvalidArgument(10022).
关于如何使用BufferList没有任何示例或文档,我正在做的事情是有意义的(无论如何).
有人可以指出一个示例程序或代码片段吗?
我正在把头发撕掉,剩下的不多了......
这基本上是我在做什么(e是SocketAsyncEventArgs和lSocket是我用于SetBuffer的相同套接字,它有效)
// null the buffer since we will use a buffer list
e.SetBuffer(null, 0, 0);
// create a bufferlist
e.BufferList = new List<ArraySegment<byte>>();
// create the bufferlist with the network header and the response bytes
e.BufferList.Add(new ArraySegment<byte>(lTxBytes)); // add the 4 character total length
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lTx.Identity))); // echo back the incoming sequence number
e.BufferList.Add(new ArraySegment<byte>(Encoding.ASCII.GetBytes(lResponse)));
// *** the SendAsync always completes IMMEDIATELY (returns false) gets SocketError InvalidArgument (10022)
if (lSocket.SendAsync(e) == false)
{
// …Run Code Online (Sandbox Code Playgroud) Socket具有这些新的异步方法,因为.NET 3.5与SocketAsyncEventArgs(例如Socket.SendAsync())一起使用,有利于它们使用IO完成端口并避免需要继续分配.
我们创建了一个名为UdpStream的类,它具有简单的接口 - 只需StartSend和Completed事件.它分配两个SocketAsyncEventArgs,一个用于发送,一个用于接收.StartSend只是使用SendAsync调度消息,并且每秒调用大约10次.我们在接收SocketAsyncEventArgs上使用Completed事件,并在处理完每个事件后,我们所有的ReceiveAsync都会形成一个接收循环.同样,我们每秒大约收到10次.
我们的系统需要支持多达500个这些UdpStream对象.换句话说,我们的服务器将与500个不同的IP端点同时通信.
我注意到在MSDN SocketAsyncEventArgs示例中他们分配了N x SocketAsyncEventArgs,一个用于您希望一次处理的每个未完成的接收操作.我不清楚这与我们的场景究竟有什么关系 - 在我看来,也许我们没有得到SocketAsyncEventArgs的好处,因为我们只是为每个端点分配一个.如果我们最终获得500个SocketAsyncEventArgs,我认为我们将无法获益.也许我们仍然可以从IO完成端口获得一些好处?
在扩展到500时,此设计是否正确使用SocketAsyncEventArgs?
对于我们使用单个"UdpStream"的情况,使用SocketAsyncEventArgs与使用旧的Begin/End API相比有什么好处?
是否有正当理由不TcpListener用于实现高性能/高吞吐量TCP服务器而不是SocketAsyncEventArgs?
我已经实现了这个高性能/高吞吐量的 TCP 服务器,它使用SocketAsyncEventArgs了一个大的预先分配的byte数组和SocketAsyncEventArgs用于接受和接收的池来处理那些固定缓冲区,使用一些低级的东西和闪亮的智能组合在一起,经历了各种各样的麻烦带有一些 TPL 数据流和一些 Rx 的代码,它工作得很好;在这项工作中几乎是教科书 - 实际上我已经从其他人的代码中学到了 80% 以上的这些东西。
但是也存在一些问题和顾虑:
byte数组):使用SocketAsyncEventArgs池需要预先分配。因此,为了处理 100000 个并发连接(更糟糕的情况,即使在不同的端口上),一大堆 RAM 无用地徘徊在那里;预先分配(即使这些条件只是在某些时候满足,服务器每天应该能够处理 1 或 2 个这样的峰值)。TcpListener实际上效果很好:我实际上已经进行TcpListener了测试(使用了一些技巧,例如AcceptTcpClient在专用线程上使用,而不是 async
版本,然后将接受的连接发送到 a
ConcurrentQueue而不是Task就地创建s 等)和最新版本的 . NET,它运行得非常好,几乎与SocketAsyncEventArgs.那么为什么我没有看到TcpListener在任何地方使用并且每个人(包括我自己)都在使用SocketAsyncEventArgs?我错过了什么吗?
我在C#.NET 4.0中处理一个庞大的项目.有一个从System.Net.Sockets继承的自定义类.SocketAsyncEventArgs类.类似于以下内容:
public class SocketTaskArgs : SocketAsyncEventArgs
{
public SocketTaskArgs()
{
Completed += someEventhHandler;
}
public void CleanUp()
{
Completed -= someEventhHandler;
}
/*
There is a lot of code here that is unimportant at the moment.
*/
}
Run Code Online (Sandbox Code Playgroud)
所以,我想将CleanUp()方法的内容移到Dispose(bool)方法.
首先,我检查了基类的源代码 - SocketAsyncEventArgs(使用Go To Definition,因此我将元数据视为源代码).我发现,这个类实现了IDisposable接口.很好,我只需要覆盖Dispose(bool)方法,不是吗?(有关详细信息,请参阅MSDN上的IDisposable接口," IDisposable和继承层次结构 "部分).对我来说没什么新东西......不幸的是,SocketAsyncEventArgs类实现如下:
public class SocketAsyncEventArgs : EventArgs, IDisposable
{
public void Dispose();
//some other stuff here
}
Run Code Online (Sandbox Code Playgroud)
这意味着,没有办法如何覆盖Dispose(bool)方法,因为它实现为私有而不是受保护 ...... 这是什么原因?
接下来,我在MSDN上阅读有关 …
private void ProcessReceive(SocketAsyncEventArgs e)
{
// Check if the remote host closed the connection.
if (e.BytesTransferred > 0)
{
if (e.SocketError == SocketError.Success)
{
Token token = e.UserToken as Token;
token.SetData(e);
Socket s = token.Connection;
if (s.Available == 0)
{
Boolean willRaiseEvent = false;
// GET DATA TO SEND
byte[] sendBuffer = token.GetRetBuffer();
// this.bufferSize IS SocketAsyncEventArgs buffer SIZE
byte[] tempBuffer = new byte[this.bufferSize];
int offset = 0;
int size = (int)Math.Ceiling((double)sendBuffer.Length / (double)this.bufferSize);
for (int i = 0; i …Run Code Online (Sandbox Code Playgroud) 我想知道哪种异步类型在开发速度和稳定性方面都是最好的.我正在编写一个概念证明网络应用程序,它必须支持1000个concurent客户端.
每个客户端每秒发送大约5个30字节的数据包.服务器每秒发送大约5个200字节的数据包.
我从早期的测试中得到了这些数字,带有阻塞套接字.我认为我应该使用SocketAsyncEventArgs导致高吞吐量,但开发时间也需要更长的时间.
谢谢
c# ×6
sockets ×6
.net ×3
asynchronous ×2
dispose ×1
idisposable ×1
inheritance ×1
networking ×1
sendasync ×1
system.net ×1
tcp ×1
tcplistener ×1
tcpserver ×1
windows ×1