您的位置:首页 > 编程语言

完成端口重叠I/O模型的服务器中,如何存储和管理数万个socket句柄—IOCP代码

2013-01-30 00:15 441 查看

(转载)完成端口重叠I/O模型的服务器中,如何存储和管理数万个socket句柄—IOCP代码

2011-01-27 15:18:34| 分类:

网络服务编程技术 | 标签:
|字号大中小
订阅

完成端口重叠I/O模型的服务器中,存储和管理数万个socket句柄 收藏

---------------------------------------------------------------

链表吧,,要么HASH链表,hehe..

---------------------------------------------------------------

根本就不可能建立几十万个连接

4.8 - How many simultaneous sockets can I have open with Winsock?

On Windows 95 derivatives, there's a quite-low limit imposed by the kernel: 100 connections. You can increase this limit by editing the registry key HKLM\System\CurrentControlSet\Services\VxD\MSTCP\MaxConnections. On Windows 95,
the key is a DWORD; on Windows 98/ME, it's a string. I've seen some reports of instability when this value is increased to more than a few times its default value.

On Windows NT derivatives, anecdotal evidence puts the limit somewhere in the 1000s of connections neighborhood if you use overlapped I/O. (Other I/O strategies hit their own performance limits on Windows before you get to
thousands of simultaneous connections.) The specific limit is dependent on how much physical memory your server has, and how busy the connections are:

The Memory Factor: According to Microsoft, the WinNT and successor kernels allocate sockets out of the non-paged memory pool. (That is, memory that cannot be swapped to the page file by the virtual memory subsystem.) The
size of this pool is necessarily fixed, and is dependent on the amount of physical memory in the system. On Intel x86 machines, the non-paged memory pool stops growing at 1/8 the size of physical memory, with a hard maximum
of 128 megabytes for Windows NT 4.0, and 256 megabytes for Windows 2000. Thus for NT 4, the size of the non-paged pool stops increasing once the machine has 1 GB of physical memory. On Win2K, you hit the wall at 2
GB.

The "Busy-ness" Factor: The amount of data associated with each socket varies depending on how that socket's used, but the minimum size is around 2 KB. Overlapped I/O buffers also eat into the non-paged pool, in blocks of
4 KB. (4 KB is the x86's memory management unit's page size.) Thus a simplistic application that's regularly sending and receiving on a socket will tie up at least 10 KB of non-pageable memory. Assuming that simple case
of 10 KB of data per connection, the theoretical maximum number of sockets on NT 4.0 is about 12,800s, and on Win2K 25,600.

I have seen reports of a 64 MB Windows NT 4.0 machine hitting the wall at 1,500 connections, a 128 MB machine at around 4,000 connections, and a 192 MB machine maxing out at 4,700 connections. It would appear that on
these machines, each connection is using between 4 KB and 6 KB. The discrepancy between these numbers and the 10 KB number above is probably due to the fact that in these servers, not all connections were sending and
receiving all the time. The idle connections will only be using about 2 KB each.

So, adjusting our "average" size down to 6 KB per socket, NT 4.0 could handle about 22,000 sockets and Win2K about 44,000 sockets. The largest value I've seen reported is 16,000 sockets on Windows NT 4.0. This lower actual
value is probably partially due to the fact that the entire non-paged memory pool isn't available to a single program. Other running programs (such as core OS services) will be competing with yours for space in the non-paged
memory pool.

---------------------------------------------------------------

要取得高效,可以同时采用TCP和UDP,支持UDP的用户就让他使用udp.还要考虑分布式的结构,像emule和bt一样,不要把太多的工作放在服务器上

---------------------------------------------------------------

<<Network Programming for Microsoft Windows 2nd>>有个技术统计,采用IOCP时:

Attempted/Connected: 50,000/49,997

Memory Used (KB): 242,272

Non-Paged Pool: 148,192

CPU Usage: 55–65%

Threads: 2

Throughput (Send/ Receive Bytes Per Second):4,326,946/4,326,496

(The server was a Pentium 4 1.7 GHz Xeon with 768 MB memory)

所以接受几万个连接是可能的,但要稳定处理就有赖于你的服务器性能和程序的健壮性.

如果要处理更多的连接,可能就要前面几楼提到的集群或者UDP了.

也许ACE是个选择,但没有深入了解过:P

---------------------------------------------------------------

网络游戏服务器,1台服务器最多也就能接受几百上千个连接

集群有以下几种思路

1,不同功能分别用不同服务器实现,比如数据库操作的程序和游戏程序分开

2,玩家档案采用同一个数据库,但是玩家可以进入不同的服务器,同一个服务器的玩家可以交流,不同服务器的不行

3,每个服务器是一个单独的区域,数据和游戏都不同

目前没听说过有真正做到负载均衡的集群游戏服务器

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Garfield/archive/2005/02/22/298000.aspx

完成端口代码 收藏

//采用完成端口的代理服务器原型代码

http://www.vckbase.com/code/listcode.asp?mclsid=9&sclsid=901

---------------------------------------------------------------

http://www.vctop.com/View.Asp?ID=484&CateID=1

---------------------------------------------------------------

服务器程序:

http://www.cnxbb.com/bcb/xbb_server_iocp.rar

模拟多客户端程序

http://www.cnxbb.com/bcb/EchoClient.rar

---------------------------------------------------------------

// Compile:

//

// cl -o callback callback.cpp ws2_32.lib

//

// Command Line Options:

//

// callback.exe

//

// Note: There are no command line options for this sample.

//

// 阻塞模式+重叠模型+完成例程机制,王天平,2003-06-20

//

#include <winsock2.h>

#include <windows.h>

#include <stdio.h>

#define PORT 5150

#define DATA_BUFSIZE 8192

//套接字信息数组单元结构

typedef struct _SOCKET_INFORMATION {

OVERLAPPED Overlapped;//重叠结构

SOCKET Socket;//套接字

CHAR Buffer[DATA_BUFSIZE];//WSARecv/WSASend 数据缓冲区指针

WSABUF DataBuf;//WSARecv/WSASend 数据缓冲区

DWORD BytesSEND;//发送字节数

DWORD BytesRECV;//接收字节数

} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;

void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,

LPWSAOVERLAPPED Overlapped, DWORD InFlags);

DWORD WINAPI WorkerThread(LPVOID lpParameter);

SOCKET AcceptSocket;

void main(void)

{

WSADATA wsaData;

SOCKET ListenSocket;

SOCKADDR_IN InternetAddr;

INT Ret;

HANDLE ThreadHandle;

DWORD ThreadId;

WSAEVENT AcceptEvent;

if ((Ret = WSAStartup(0x0202,&wsaData)) != 0)

{

printf("WSAStartup failed with error %d\n", Ret);

WSACleanup();

return;

}

if ((ListenSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,

WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)

{

printf("Failed to get a socket %d\n", WSAGetLastError());

return;

}

InternetAddr.sin_family = AF_INET;

InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);

InternetAddr.sin_port = htons(PORT);

if (bind(ListenSocket, (PSOCKADDR) &InternetAddr,

sizeof(InternetAddr)) == SOCKET_ERROR)

{

printf("bind() failed with error %d\n", WSAGetLastError());

return;

}

if (listen(ListenSocket, 5))

{

printf("listen() failed with error %d\n", WSAGetLastError());

return;

}

if ((AcceptEvent = WSACreateEvent()) == WSA_INVALID_EVENT)

{

printf("WSACreateEvent() failed with error %d\n", WSAGetLastError());

return;

}

// Create a worker thread to service completed I/O requests.

if ((ThreadHandle = CreateThread(NULL, 0, WorkerThread, (LPVOID) AcceptEvent, 0, &ThreadId)) == NULL)

{

printf("CreateThread failed with error %d\n", GetLastError());

return;

}

while(TRUE)

{

AcceptSocket = accept(ListenSocket, NULL, NULL);

if (WSASetEvent(AcceptEvent) == FALSE)

{

printf("WSASetEvent failed with error %d\n", WSAGetLastError());

return;

}

}

}

DWORD WINAPI WorkerThread(LPVOID lpParameter)

{

DWORD Flags;

LPSOCKET_INFORMATION SocketInfo;

WSAEVENT EventArray[1];

DWORD Index;

DWORD RecvBytes;

// Save the accept event in the event array.

EventArray[0] = (WSAEVENT) lpParameter;

while(TRUE)

{

// Wait for accept() to signal an event and also process WorkerRoutine() returns.

while(TRUE)

{

Index = WSAWaitForMultipleEvents(1, EventArray, FALSE, WSA_INFINITE, TRUE);

if (Index == WSA_WAIT_FAILED)

{

printf("WSAWaitForMultipleEvents failed with error %d\n", WSAGetLastError());

return FALSE;

}

if (Index != WAIT_IO_COMPLETION)

{

// An accept() call
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: