📄 iocpclient.cpp
字号:
break;
case 'c': // Number of connections to make
if (i+1 >= argc)
usage(argv[0]);
gConnectionCount = 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 'n': // server address/name to connect to
if (i+1 >= argc)
usage(argv[0]);
gServerAddr = argv[++i];
break;
case 'o': // overlapped count
if (i+1 >= argc)
usage(argv[0]);
gOverlappedCount = atol(argv[++i]);
break;
case 'p': // local port
if (i+1 >= argc)
usage(argv[0]);
gLocalPort = (USHORT) atoi(argv[++i]);
break;
case 'r': // Use the QOS packet scheduler
if (i+1 >= argc)
usage(argv[0]);
gRateLimit = atol(argv[++i]);
break;
case 't': // Use TransmitFile instead of sends
gTransmitFile = TRUE;
if (i+1 >= argc)
usage(argv[0]);
gFileSize = atol(argv[++i]);
break;
case 'x': // Number of sends to post total
if (i+1 >= argc)
usage(argv[0]);
gSendCount = atol(argv[++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)
{
printf("Bytes sent : %lu\n", gBytesSent);
printf("Bytes received : %lu\n", gBytesRead);
printf("Current Connections: %lu\n", gCurrentConnections);
printf("Total Connections : %lu\n", gTotalConnections);
printf("Connections Refused: %lu\n", gConnectionRefused);
return;
}
printf("\n");
printf("Current Connections: %lu\n", gCurrentConnections);
printf("Total Connections : %lu\n", gTotalConnections);
printf("Connections Refused: %lu\n", gConnectionRefused);
// 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);
InterlockedExchange(&gBytesSentLast, 0);
InterlockedExchange(&gBytesReadLast, 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;
rc = WSARecv(
sock->s,
&wbuf,
1,
&bytes,
&flags,
&recvobj->ol,
NULL
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostRecv: WSARecv* failed: %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
}
// Increment outstanding overlapped operations
InterlockedIncrement(&sock->OutstandingOps);
//printf("POST_READ: op %d\n", sock->OutstandingOps);
return NO_ERROR;
}
//
// 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;
sendobj->operation = OP_WRITE;
wbuf.buf = sendobj->buf;
wbuf.len = sendobj->buflen;
rc = WSASend(
sock->s,
&wbuf,
1,
&bytes,
0,
&sendobj->ol,
NULL
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostSend: WSASend* failed: %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
}
// Increment the outstanding operation count
InterlockedIncrement(&sock->OutstandingOps);
InterlockedDecrement(&sock->SendCount);
//printf("POST_SEND: op %d\n", sock->OutstandingOps);
return NO_ERROR;
}
//
// Function: PostConnect
//
// Description:
// Post an overlapped accept on a listening socket.
//
int PostConnect(SOCKET_OBJ *sock, BUFFER_OBJ *connobj)
{
DWORD bytes;
int rc;
connobj->operation = OP_CONNECT;
/*
printf("Connecting to: ");
PrintAddress((SOCKADDR *)&connobj->addr, connobj->addrlen);
printf("\n");
*/
rc = sock->lpfnConnectEx(
sock->s,
(SOCKADDR *)&connobj->addr,
connobj->addrlen,
connobj->buf,
connobj->buflen,
&bytes,
&connobj->ol
);
if (rc == FALSE)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostConnect: ConnectEx failed: %d\n",
WSAGetLastError());
return SOCKET_ERROR;
}
}
// Increment the outstanding overlapped count for this socket
InterlockedIncrement(&sock->OutstandingOps);
//printf("POST_CONNECT: op %d\n", sock->OutstandingOps);
return NO_ERROR;
}
//
// Function: PostTransmitFile
//
// Description:
// Post a TransmitFile operation on the given socket connection.
//
int PostTransmitFile(SOCKET_OBJ *sock, BUFFER_OBJ *tfobj)
{
int rc;
tfobj->operation = OP_TRANSMIT;
tfobj->hFile = gTempFile;
// Zero out the OVERLAPPED, the offset must be zero
memset(&tfobj->ol, 0, sizeof(tfobj->ol));
rc = sock->lpfnTransmitFile(
sock->s,
tfobj->hFile,
0,
0,
&tfobj->ol,
NULL,
0
);
if (rc == FALSE)
{
if (WSAGetLastError() != WSA_IO_PENDING)
{
fprintf(stderr, "PostTransmitFile: TransmitFile failed: %d\n",
WSAGetLastError());
return SOCKET_ERROR;
}
}
// Increment the outstanding overlapped count for this socket
InterlockedIncrement(&sock->OutstandingOps);
InterlockedDecrement(&sock->SendCount);
return NO_ERROR;
}
//
// Function: HandleIo
//
// Description:
// This function handles the IO on a socket. In the event of a receive, the
// completed receive is posted again. For completed accepts, another AcceptEx
// is posted. For completed sends, the buffer is freed.
//
int HandleIo(SOCKET_OBJ *sock, BUFFER_OBJ *buf, DWORD BytesTransfered, DWORD error)
{
BUFFER_OBJ *recvobj=NULL, // Used to post new receives on accepted connections
*sendobj=NULL; // Used to post new sends for data received
BOOL bCleanupSocket;
int rc,
i;
bCleanupSocket = FALSE;
if (error != NO_ERROR)
{
// An error occured on a TCP socket, free the associated per I/O buffer
// and see if there are any more outstanding operations. If so we must
// wait until they are complete as well.
//
printf("error = %d\n", error);
closesocket(sock->s);
sock->s = INVALID_SOCKET;
if (buf->operation == OP_CONNECT)
{
if (error == WSAECONNREFUSED)
{
InterlockedIncrement(&gConnectionRefused);
}
FreeBufferObj(buf);
RemoveSocketObj(&gConnectionList, sock);
FreeSocketObj(sock);
if (gConnectionList == NULL)
return 0;
}
else
{
FreeBufferObj(buf);
if (sock->OutstandingOps == 0)
{
RemoveSocketObj(&gConnectionList, sock);
FreeSocketObj(sock);
}
}
return SOCKET_ERROR;
}
else
{
if (buf->operation == OP_CONNECT)
{
int optval=1;
// Update counters
InterlockedIncrement(&gCurrentConnections);
InterlockedIncrement(&gTotalConnections);
InterlockedExchangeAdd(&gBytesSent, BytesTransfered);
InterlockedExchangeAdd(&gBytesSentLast, BytesTransfered);
// Need to update the socket context in order to use the shutdown API
rc = setsockopt(
sock->s,
SOL_SOCKET,
SO_UPDATE_CONNECT_CONTEXT,
(char *)&optval,
sizeof(optval)
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "setsockopt: SO_UPDATE_CONNECT_CONTEXT failed: %d\n",
WSAGetLastError());
}
sock->bConnected = TRUE;
// Post the specified number of receives on the succeeded connection
for(i=0; i < gOverlappedCount ;i++)
{
recvobj = GetBufferObj(gBufferSize);
if (PostRecv(sock, recvobj) != NO_ERROR)
{
FreeBufferObj(recvobj);
bCleanupSocket = TRUE;
break;
}
}
for(i=0; ((i < gOverlappedCount) && (!bCleanupSocket)) ;i++)
{
sendobj = GetBufferObj(gBufferSize);
if (gTransmitFile)
{
rc = PostTransmitFile(sock, sendobj);
}
else
{
rc = PostSend(sock, sendobj);
}
if (rc != NO_ERROR)
{
FreeBufferObj(sendobj);
bCleanupSocket = TRUE;
break;
}
if (sock->SendCount == 0)
break;
}
FreeBufferObj(buf);
}
else if (buf->operation == OP_READ)
{
//
// Receive completed successfully
//
if ((BytesTransfered > 0) && (!sock->bClosing))
{
InterlockedExchangeAdd(&gBytesRead, BytesTransfered);
InterlockedExchangeAdd(&gBytesReadLast, BytesTransfered);
if (PostRecv(sock, buf) != NO_ERROR)
{
// In the event the recv fails, clean up the connection
FreeBufferObj(buf);
bCleanupSocket = TRUE;
}
}
else
{
// Graceful close - the receive returned 0 bytes read
sock->bClosing = TRUE;
// Free the receive buffer
FreeBufferObj(buf);
//printf("zero byte read\n");
}
}
else if (buf->operation == OP_WRITE)
{
// Update the counters
InterlockedExchangeAdd(&gBytesSent, BytesTransfered);
InterlockedExchangeAdd(&gBytesSentLast, BytesTransfered);
// If there are sends to be made, call PostSend again
EnterCriticalSection(&sock->SockCritSec);
if (gRateLimit == -1)
{
// If no rate limiting just repost the send
if (sock->SendCount > 0)
{
rc = PostSend(sock, buf);
if (rc != NO_ERROR)
{
bCleanupSocket = TRUE;
}
}
else
{
// Otherwise, shutdown the socket
if (shutdown(sock->s, SD_SEND) == SOCKET_ERROR)
{
printf("shutdown failed: %d (handle = 0x%p\n", WSAGetLastError(), sock->s);
}
FreeBufferObj(buf);
}
}
else
{
// If rate limiting is turned on then save off the send object for
// sending by the rate thread.
//
if (sock->SendCount > 0)
{
buf->next = sock->Repost;
sock->Repost = buf;
}
else
{
// Otherwise, shutdown the socket
if (shutdown(sock->s, SD_SEND) == SOCKET_ERROR)
{
printf("shutdown failed: %d (handle = 0x%p\n", WSAGetLastError(), sock->s);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -