📄 iocpserver.cpp
字号:
//
// Function: RemovePendingAccept
//
// Description:
// Removes the indicated accept buffer object from the list of pending
// accepts in the listening object.
//
void RemovePendingAccept(LISTEN_OBJ *listenobj, BUFFER_OBJ *obj)
{
BUFFER_OBJ *ptr=NULL, *prev=NULL;
EnterCriticalSection(&listenobj->ListenCritSec);
// Search list until we find the object
ptr = listenobj->PendingAccepts;
while ( (ptr) && (ptr != obj) )
{
prev = ptr;
ptr = ptr->next;
}
if (prev)
{
// Object is somewhere after the first entry
prev->next = obj->next;
}
else
{
// Object is the first entry
listenobj->PendingAccepts = obj->next;
}
LeaveCriticalSection(&listenobj->ListenCritSec);
}
//
// Function: GetBufferObj
//
// Description:
// Allocate a BUFFER_OBJ. A lookaside list is maintained to increase performance
// as these objects are allocated frequently.
//
BUFFER_OBJ *GetBufferObj(int buflen)
{
BUFFER_OBJ *newobj=NULL;
EnterCriticalSection(&gBufferListCs);
if (gFreeBufferList == NULL)
{
// Allocate the object
newobj = (BUFFER_OBJ *)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(BUFFER_OBJ) + (sizeof(BYTE) * buflen)
);
if (newobj == NULL)
{
fprintf(stderr, "GetBufferObj: HeapAlloc failed: %d\n", GetLastError());
}
}
else
{
newobj = gFreeBufferList;
gFreeBufferList = newobj->next;
newobj->next = NULL;
}
LeaveCriticalSection(&gBufferListCs);
if (newobj)
{
newobj->buf = (char *)(((char *)newobj) + sizeof(BUFFER_OBJ));
newobj->buflen = buflen;
newobj->addrlen = sizeof(newobj->addr);
}
return newobj;
}
//
// Function: FreeBufferObj
//
// Description:
// Free the buffer object. This adds the object to the free lookaside list.
//
void FreeBufferObj(BUFFER_OBJ *obj)
{
EnterCriticalSection(&gBufferListCs);
memset(obj, 0, sizeof(BUFFER_OBJ) + gBufferSize);
obj->next = gFreeBufferList;
gFreeBufferList = obj;
LeaveCriticalSection(&gBufferListCs);
}
//
// Function: GetSocketObj
//
// Description:
// Allocate a socket object and initialize its members. A socket object is
// allocated for each socket created (either by socket or accept).
// Socket objects are returned from a lookaside list if available. Otherwise,
// a new object is allocated.
//
SOCKET_OBJ *GetSocketObj(SOCKET s, int af)
{
SOCKET_OBJ *sockobj=NULL;
EnterCriticalSection(&gSocketListCs);
if (gFreeSocketList == NULL)
{
sockobj = (SOCKET_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOCKET_OBJ));
if (sockobj == NULL)
{
fprintf(stderr, "GetSocketObj: HeapAlloc failed: %d\n", GetLastError());
}
else
{
InitializeCriticalSection(&sockobj->SockCritSec);
}
}
else
{
sockobj = gFreeSocketList;
gFreeSocketList = sockobj->next;
sockobj->next = NULL;
}
LeaveCriticalSection(&gSocketListCs);
// Initialize the members
if (sockobj)
{
sockobj->s = s;
sockobj->af = af;
}
return sockobj;
}
//
// Function: FreeSocketObj
//
// Description:
// Frees a socket object. The object is added to the lookaside list.
//
void FreeSocketObj(SOCKET_OBJ *obj)
{
CRITICAL_SECTION cstmp;
BUFFER_OBJ *ptr=NULL;
// Close the socket if it hasn't already been closed
if (obj->s != INVALID_SOCKET)
{
printf("FreeSocketObj: closing socket\n");
closesocket(obj->s);
obj->s = INVALID_SOCKET;
}
EnterCriticalSection(&gSocketListCs);
cstmp = obj->SockCritSec;
memset(obj, 0, sizeof(SOCKET_OBJ));
obj->SockCritSec = cstmp;
obj->next = gFreeSocketList;
gFreeSocketList = obj;
LeaveCriticalSection(&gSocketListCs);
}
//
// Function: ValidateArgs
//
// Description:
// Parses the command line arguments and sets up some global
// variables.
//
void ValidateArgs(int argc, char **argv)
{
int i;
for(i=1; i < argc ;i++)
{
if (((argv[i][0] != '/') && (argv[i][0] != '-')) || (strlen(argv[i]) < 2))
usage(argv[0]);
else
{
switch (tolower(argv[i][1]))
{
case 'a': // address family - IPv4 or IPv6
if (i+1 >= argc)
usage(argv[0]);
if (argv[i+1][0] == '4')
gAddressFamily = AF_INET;
else if (argv[i+1][0] == '6')
gAddressFamily = AF_INET6;
else
usage(argv[0]);
i++;
break;
case 'b': // buffer size for send/recv
if (i+1 >= argc)
usage(argv[0]);
gBufferSize = atol(argv[++i]);
break;
case 'e': // endpoint - port number
if (i+1 >= argc)
usage(argv[0]);
gBindPort = argv[++i];
break;
case 'l': // local address for binding
if (i+1 >= argc)
usage(argv[0]);
gBindAddr = argv[++i];
break;
case 'o': // overlapped count
if (i+1 >= argc)
usage(argv[0]);
if (strlen(argv[i]) == 2) // Overlapped accept initial count
{
gInitialAccepts = atol(argv[++i]);
}
else if (strlen(argv[i]) == 3)
{
if (tolower(argv[i][2]) == 'a')
gMaxAccepts = atol(argv[++i]);
else if (tolower(argv[i][2]) == 's')
gMaxSends = atol(argv[++i]);
else if (tolower(argv[i][2]) == 'r')
gMaxReceives = atol(argv[++i]);
else
usage(argv[0]);
}
else
{
usage(argv[0]);
}
break;
default:
usage(argv[0]);
break;
}
}
}
}
//
// Function: PrintStatistics
//
// Description:
// Print the send/recv statistics for the server
//
void PrintStatistics()
{
ULONG bps, tick, elapsed, cps;
tick = GetTickCount();
elapsed = (tick - gStartTime) / 1000;
if (elapsed == 0)
return;
printf("\n");
// Calculate average bytes per second
bps = gBytesSent / elapsed;
printf("Average BPS sent: %lu [%lu]\n", bps, gBytesSent);
bps = gBytesRead / elapsed;
printf("Average BPS read: %lu [%lu]\n", bps, gBytesRead);
elapsed = (tick - gStartTimeLast) / 1000;
if (elapsed == 0)
return;
// Calculate bytes per second over the last X seconds
bps = gBytesSentLast / elapsed;
printf("Current BPS sent: %lu\n", bps);
bps = gBytesReadLast / elapsed;
printf("Current BPS read: %lu\n", bps);
cps = gConnectionsLast / elapsed;
printf("Current conns/sec: %lu\n", cps);
printf("Total connections: %lu\n", gConnections);
InterlockedExchange(&gBytesSentLast, 0);
InterlockedExchange(&gBytesReadLast, 0);
InterlockedExchange(&gConnectionsLast, 0);
gStartTimeLast = tick;
}
//
// Function: PostRecv
//
// Description:
// Post an overlapped receive operation on the socket.
//
int PostRecv(SOCKET_OBJ *sock, BUFFER_OBJ *recvobj)
{
WSABUF wbuf;
DWORD bytes,
flags;
int rc;
recvobj->operation = OP_READ;
wbuf.buf = recvobj->buf;
wbuf.len = recvobj->buflen;
flags = 0;
EnterCriticalSection(&sock->SockCritSec);
rc = WSARecv(
sock->s,
&wbuf,
1,
&bytes,
&flags,
&recvobj->ol,
NULL
);
if (rc == SOCKET_ERROR)
{
rc = NO_ERROR;
if (WSAGetLastError() != WSA_IO_PENDING)
{
dbgprint("PostRecv: WSARecv* failed: %d\n", WSAGetLastError());
rc = SOCKET_ERROR;
}
}
if (rc == NO_ERROR)
{
// Increment outstanding overlapped operations
InterlockedIncrement(&sock->OutstandingRecv);
}
LeaveCriticalSection(&sock->SockCritSec);
return rc;
}
//
// Function: PostSend
//
// Description:
// Post an overlapped send operation on the socket.
//
int PostSend(SOCKET_OBJ *sock, BUFFER_OBJ *sendobj)
{
WSABUF wbuf;
DWORD bytes;
int rc, err;
sendobj->operation = OP_WRITE;
wbuf.buf = sendobj->buf;
wbuf.len = sendobj->buflen;
EnterCriticalSection(&sock->SockCritSec);
rc = WSASend(
sock->s,
&wbuf,
1,
&bytes,
0,
&sendobj->ol,
NULL
);
if (rc == SOCKET_ERROR)
{
rc = NO_ERROR;
if ((err = WSAGetLastError()) != WSA_IO_PENDING)
{
if (err == WSAENOBUFS)
DebugBreak();
dbgprint("PostSend: WSASend* failed: %d [internal = %d]\n", WSAGetLastError(), sendobj->ol.Internal);
rc = SOCKET_ERROR;
}
}
if (rc == NO_ERROR)
{
// Increment the outstanding operation count
InterlockedIncrement(&sock->OutstandingSend);
InterlockedIncrement(&gOutstandingSends);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -