- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我想使用 SocketAsyncEventArgs 事件创建一个异步套接字服务器。
服务器应该同时管理大约 1000 个连接。处理每个数据包逻辑的最佳方式是什么?
服务器设计基于this MSDN example ,所以每个套接字都会有自己的 SocketAsyncEventArgs 来接收数据。
在接收函数中执行逻辑操作。不会产生任何开销,但由于下一个 ReceiveAsync() 调用不会在逻辑完成之前完成,因此无法从套接字读取新数据。我的两个主要问题是:如果客户端发送大量数据并且逻辑处理繁重,系统将如何处理它(因为缓冲区已满而丢失数据包)?另外,如果所有客户端同时发送数据,是否会有1000个线程,或者有内部限制,新线程不能在另一个线程执行完成之前启动?
使用队列。接收函数将非常短并且执行速度很快,但是由于队列的存在,你会有相当大的开销。问题是,如果你的工作线程在服务器负载很重的情况下不够快,你的队列可能会变满,所以你可能不得不强制丢弃数据包。您还会遇到生产者/消费者问题,这可能会降低整个队列的速度,因为有很多锁。
那么什么是更好的设计、接收函数中的逻辑、工作线程中的逻辑或我迄今为止错过的任何完全不同的东西。
关于数据发送的另一个任务。
将 SocketAsyncEventArgs 绑定(bind)到套接字(模拟接收事件)并使用缓冲系统对几个小数据包进行一次发送调用是否更好(假设数据包有时会!一个接一个地直接发送) 或者对每个数据包使用不同的 SocketAsyncEventArgs 并将它们存储在池中以重用它们?
最佳答案
要有效地实现异步套接字,每个套接字将需要超过 1 个 SocketAsyncEventArgs。每个 SocketAsyncEventArgs 中的 byte[] 缓冲区也存在问题。简而言之,只要发生托管 - native 转换(发送/接收),字节缓冲区就会被固定。如果您根据需要分配 SocketAsyncEventArgs 和字节缓冲区,由于碎片化和 GC 无法压缩固定内存,您可能会遇到许多客户端的 OutOfMemoryExceptions。
处理此问题的最佳方法是创建一个 SocketBufferPool 类,该类将在应用程序首次启动时分配大量字节和 SocketAsyncEventArgs,这样固定的内存将是连续的。然后根据需要简单地重新使用池中的缓冲区。
在实践中,我发现最好围绕 SocketAsyncEventArgs 创建一个包装类和一个 SocketBufferPool 类来管理资源的分配。
例如,这是 BeginReceive 方法的代码:
private void BeginReceive(Socket socket)
{
Contract.Requires(socket != null, "socket");
SocketEventArgs e = SocketBufferPool.Instance.Alloc();
e.Socket = socket;
e.Completed += new EventHandler<SocketEventArgs>(this.HandleIOCompleted);
if (!socket.ReceiveAsync(e.AsyncEventArgs)) {
this.HandleIOCompleted(null, e);
}
}
这是 HandleIOCompleted 方法:
private void HandleIOCompleted(object sender, SocketEventArgs e)
{
e.Completed -= this.HandleIOCompleted;
bool closed = false;
lock (this.sequenceLock) {
e.SequenceNumber = this.sequenceNumber++;
}
switch (e.LastOperation) {
case SocketAsyncOperation.Send:
case SocketAsyncOperation.SendPackets:
case SocketAsyncOperation.SendTo:
if (e.SocketError == SocketError.Success) {
this.OnDataSent(e);
}
break;
case SocketAsyncOperation.Receive:
case SocketAsyncOperation.ReceiveFrom:
case SocketAsyncOperation.ReceiveMessageFrom:
if ((e.BytesTransferred > 0) && (e.SocketError == SocketError.Success)) {
this.BeginReceive(e.Socket);
if (this.ReceiveTimeout > 0) {
this.SetReceiveTimeout(e.Socket);
}
} else {
closed = true;
}
if (e.SocketError == SocketError.Success) {
this.OnDataReceived(e);
}
break;
case SocketAsyncOperation.Disconnect:
closed = true;
break;
case SocketAsyncOperation.Accept:
case SocketAsyncOperation.Connect:
case SocketAsyncOperation.None:
break;
}
if (closed) {
this.HandleSocketClosed(e.Socket);
}
SocketBufferPool.Instance.Free(e);
}
以上代码包含在将引发 DataReceived 和 DataSent 事件的 TcpSocket 类中。需要注意的一件事是 SocketAsyncOperation.ReceiveMessageFrom: block;如果套接字没有错误,它会立即启动另一个 BeginReceive(),它将从池中分配另一个 SocketEventArgs。
另一个重要注意事项是在 HandleIOComplete 方法中设置的 SocketEventArgs SequenceNumber 属性。尽管异步请求将按照排队的顺序完成,但您仍然会受到其他线程竞争条件的影响。由于代码在引发 DataReceived 事件之前调用 BeginReceive,因此服务于原始 IOCP 的线程可能会在调用 BeginReceive 之后但在引发事件之前阻塞,而第二个异步接收在首先引发 DataReceived 事件的新线程上完成。虽然这是一种相当罕见的边缘情况,但它可能会发生,并且 SequenceNumber 属性使消费应用程序能够确保以正确的顺序处理数据。
另一个需要注意的领域是异步发送。通常,异步发送请求将同步完成(如果调用同步完成,则 SendAsync 将返回 false)并且会严重降低性能。在 IOCP 上返回的异步调用的额外开销实际上会导致比简单地使用同步调用更差的性能。异步调用需要两次内核调用和一次堆分配,而同步调用发生在堆栈上。
希望对您有所帮助, 账单
关于c# - 使用 SocketAsyncEventArgs 的服务器设计,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1538348/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!