📄 overserver.cpp
字号:
}
//
// 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]);
gOverlappedCount = atol(argv[++i]);
break;
case 'p': // protocol - TCP or UDP
if (i+1 >= argc)
usage(argv[0]);
if (_strnicmp(argv[i+1], "tcp", 3) == 0)
{
gProtocol = IPPROTO_TCP;
gSocketType = SOCK_STREAM;
}
else if (_strnicmp(argv[i+1], "udp", 3) == 0)
{
gProtocol = IPPROTO_UDP;
gSocketType = SOCK_DGRAM;
}
else
usage(argv[0]);
i++;
break;
default:
usage(argv[0]);
break;
}
}
}
}
//
// Function: PrintStatistics
//
// Description:
// Print the send/recv statistics for the server
//
void PrintStatistics()
{
ULONG bps, tick, elapsed;
tick = GetTickCount();
elapsed = (tick - gStartTime) / 1000;
if (elapsed == 0)
return;
printf("\n");
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;
bps = gBytesSentLast / elapsed;
printf("Current BPS sent: %lu\n", bps);
bps = gBytesReadLast / elapsed;
printf("Current BPS read: %lu\n", bps);
printf("Total Connections : %lu\n", gTotalConnections);
printf("Current Connections: %lu\n", gCurrentConnections);
InterlockedExchange(&gBytesSentLast, 0);
InterlockedExchange(&gBytesReadLast, 0);
gStartTimeLast = tick;
}
//
// Function: PostRecv
//
// Description:
// Post an overlapped receive operation on the socket.
//
int PostRecv(BUFFER_OBJ *recvobj)
{
WSABUF wbuf;
DWORD bytes,
flags;
int rc=NO_ERROR;
EnterCriticalSection(&recvobj->Socket->SockCritSec);
recvobj->operation = OP_READ;
wbuf.buf = recvobj->buf;
wbuf.len = recvobj->buflen;
flags = 0;
if (gProtocol == IPPROTO_TCP)
{
rc = WSARecv(
recvobj->Socket->s,
&wbuf,
1,
&bytes,
&flags,
&recvobj->ol,
NULL
);
}
else
{
rc = WSARecvFrom(
recvobj->Socket->s,
&wbuf,
1,
&bytes,
&flags,
(SOCKADDR *)&recvobj->addr,
&recvobj->addrlen,
&recvobj->ol,
NULL
);
}
if (rc == SOCKET_ERROR)
{
rc = NO_ERROR;
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostRecv: WSARecv* failed: %d\n", WSAGetLastError());
rc = SOCKET_ERROR;
}
}
// Increment outstanding overlapped operations
InterlockedIncrement(&recvobj->Socket->OutstandingOps);
LeaveCriticalSection(&recvobj->Socket->SockCritSec);
return NO_ERROR;
}
//
// Function: PostSend
//
// Description:
// Post an overlapped send operation on the socket.
//
int PostSend(BUFFER_OBJ *sendobj)
{
WSABUF wbuf;
DWORD bytes;
int rc;
rc = NO_ERROR;
sendobj->operation = OP_WRITE;
wbuf.buf = sendobj->buf;
wbuf.len = sendobj->buflen;
EnterCriticalSection(&sendobj->Socket->SockCritSec);
if (gProtocol == IPPROTO_TCP)
{
rc = WSASend(
sendobj->Socket->s,
&wbuf,
1,
&bytes,
0,
&sendobj->ol,
NULL
);
}
else
{
rc = WSASendTo(
sendobj->Socket->s,
&wbuf,
1,
&bytes,
0,
(SOCKADDR *)&sendobj->addr,
sendobj->addrlen,
&sendobj->ol,
NULL
);
}
if (rc == SOCKET_ERROR)
{
rc = NO_ERROR;
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostSend: WSASend* failed: %d\n", WSAGetLastError());
rc = SOCKET_ERROR;
}
}
// Increment the outstanding operation count
InterlockedIncrement(&sendobj->Socket->OutstandingOps);
LeaveCriticalSection(&sendobj->Socket->SockCritSec);
return rc;
}
//
// Function: PostAccept
//
// Description:
// Post an overlapped accept on a listening socket.
//
int PostAccept(BUFFER_OBJ *acceptobj)
{
DWORD bytes;
int rc=NO_ERROR;
acceptobj->operation = OP_ACCEPT;
EnterCriticalSection(&acceptobj->Socket->SockCritSec);
// Create the client socket for an incoming connection
acceptobj->sclient = socket(acceptobj->Socket->af, SOCK_STREAM, IPPROTO_TCP);
if (acceptobj->sclient == INVALID_SOCKET)
{
fprintf(stderr, "PostAccept: socket failed: %d\n", WSAGetLastError());
return -1;
}
rc = acceptobj->Socket->lpfnAcceptEx(
acceptobj->Socket->s,
acceptobj->sclient,
acceptobj->buf,
acceptobj->buflen - ((sizeof(SOCKADDR_STORAGE) + 16) * 2),
sizeof(SOCKADDR_STORAGE) + 16,
sizeof(SOCKADDR_STORAGE) + 16,
&bytes,
&acceptobj->ol
);
if (rc == FALSE)
{
rc = NO_ERROR;
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostAccept: AcceptEx failed: %d\n",
WSAGetLastError());
rc = SOCKET_ERROR;
}
}
// Increment the outstanding overlapped count for this socket
InterlockedIncrement(&acceptobj->Socket->OutstandingOps);
LeaveCriticalSection(&acceptobj->Socket->SockCritSec);
return rc;
}
//
// Function: HandleIo
//
// Description:
// This function handles the IO on a socket. First, the events signaled
// on the socket are enuemrated, then the appropriate handler routine
// for the event is called.
//
void HandleIo(BUFFER_OBJ *buf)
{
SOCKET_OBJ *sock=NULL,
*clientobj=NULL; // New client object for accepted connections
BUFFER_OBJ *recvobj=NULL, // Used to post new receives on accepted connections
*sendobj=NULL; // Used to post sends for data received
DWORD bytes,
flags;
BOOL bFreeSocketObj;
int error,
rc;
// Extract the SOCKET_OBJ from the BUFFER_OBJ for easy reference
sock = buf->Socket;
error = NO_ERROR;
bFreeSocketObj = FALSE;
InterlockedDecrement(&sock->OutstandingOps);
// Get the results of the overlapped operation that completed
rc = WSAGetOverlappedResult(
sock->s,
&buf->ol,
&bytes,
FALSE,
&flags
);
if (rc == FALSE)
{
error = WSAGetLastError();
fprintf(stderr, "HandleIo: WSAGetOverlappedResult failed: %d\n", error);
if (gProtocol == IPPROTO_TCP)
{
// An error occured on a TCP socket, so remove this I/O and if no
// more I/O is outstanding, free the socket object. Otherwise,
// wait for the remaining I/O on this socket to complete as well.
RemoveBufferFromThread(sock, buf);
FreeBufferObj(buf);
if (InterlockedDecrement(&sock->OutstandingOps) == 0)
{
printf("Freeing socket obj in GetOverlapepdResult\n");
FreeSocketObj(sock);
}
return;
}
}
if (buf->operation == OP_ACCEPT)
{
SOCKADDR_STORAGE *LocalSockaddr=NULL,
*RemoteSockaddr=NULL;
int LocalSockaddrLen,
RemoteSockaddrLen;
// Update the counters
InterlockedExchangeAdd(&gBytesRead, bytes);
InterlockedExchangeAdd(&gBytesReadLast, bytes);
InterlockedIncrement(&gTotalConnections);
InterlockedIncrement(&gCurrentConnections);
// Retrieve the client's address
sock->lpfnGetAcceptExSockaddrs(
buf->buf,
buf->buflen - ((sizeof(SOCKADDR_STORAGE) + 16) * 2),
sizeof(SOCKADDR_STORAGE) + 16,
sizeof(SOCKADDR_STORAGE) + 16,
(SOCKADDR **)&LocalSockaddr,
&LocalSockaddrLen,
(SOCKADDR **)&RemoteSockaddr,
&RemoteSockaddrLen
);
// Under high connection stress this print slows things down
/*
printf("Received connection from: ");
PrintAddress((SOCKADDR *)RemoteSockaddr, RemoteSockaddrLen);
printf("\n");
*/
// Create a new SOCKET_OBJ for client socket
clientobj = GetSocketObj(buf->sclient, buf->Socket->af);
// Echo back any data received with the AcceptEx call
sendobj = GetBufferObj(clientobj, gBufferSize);
// Copy the data from the accept buffer to the send buffer
sendobj->buflen = bytes;
memcpy(sendobj->buf, buf->buf, bytes);
// Assign the send operation to a thread
AssignIoToThread(sendobj);
// Initiate the overlapped send
if (PostSend(sendobj) != NO_ERROR)
{
// In the event of an error, clean up the socket object
RemoveBufferFromThread(clientobj, sendobj);
FreeBufferObj(sendobj);
closesocket(clientobj->s);
clientobj->s = INVALID_SOCKET;
FreeSocketObj(clientobj);
}
PostAccept(buf);
}
else if ((buf->operation == OP_READ) && (error == NO_ERROR))
{
//
// Receive compeleted successfully
//
if ((bytes > 0) || (gProtocol == IPPROTO_UDP))
{
// Increment the counters
InterlockedExchangeAdd(&gBytesRead, bytes);
InterlockedExchangeAdd(&gBytesReadLast, bytes);
// Create a buffer to send
sendobj = buf;
sendobj->buflen = bytes;
// Initiate the send
if (PostSend(sendobj) != NO_ERROR)
{
// In the event of an error, clean up the socket object
RemoveBufferFromThread(sock, sendobj);
FreeBufferObj(sendobj);
closesocket(sock->s);
sock->s = INVALID_SOCKET;
bFreeSocketObj = TRUE;
}
}
else
{
// Graceful close
sock->bClosing = TRUE;
// Free the completed operation
RemoveBufferFromThread(sock, buf);
FreeBufferObj(buf);
// Check to see if there are more outstanding operations. If so, wait
// for them to complete; otherwise, clean up the socket object.
EnterCriticalSection(&sock->SockCritSec);
if (sock->OutstandingOps == 0)
{
closesocket(sock->s);
bFreeSocketObj = TRUE;
}
LeaveCriticalSection(&sock->SockCritSec);
}
}
else if ((buf->operation == OP_READ) && (error != NO_ERROR) && (gProtocol == IPPROTO_UDP))
{
// If a UDP receive failed, we really don't care. Just re-post it - that is
// we probably got an ICMP error.
if (PostRecv(buf) != NO_ERROR)
{
// In the event of an error, clean up the socket object
RemoveBufferFromThread(sock, buf);
FreeBufferObj(buf);
closesocket(sock->s);
sock->s = INVALID_SOCKET;
bFreeSocketObj = TRUE;
}
}
else if (buf->operation == OP_WRITE)
{
// Increment the counters
InterlockedExchangeAdd(&gBytesSent, bytes);
InterlockedExchangeAdd(&gBytesSentLast, bytes);
// See if the socket is closing, if so check to see if there are any outstanding
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -