📄 bserver.cpp
字号:
ReleaseSemaphore(ConnObj->hRecvSema, 1, NULL);
if (rc == 0)
{
break;
}
}
}
else if (gProtocol == IPPROTO_TCP)
{
// loop until the connection is closed or is aborted/terminated
while (1)
{
// Allocate the buffer for stream send/recv
BuffObj = GetBufferObj(gBufferSize);
rc = recv(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0);
BuffObj->buflen = rc;
// Queue the receive buffer for sending and signal the send thread
EnqueueBufferObj(ConnObj, BuffObj);
ReleaseSemaphore(ConnObj->hRecvSema, 1, NULL);
if (rc == 0 || rc == SOCKET_ERROR)
{
break;
}
else if (rc != SOCKET_ERROR)
{
// Increment the statistics
InterlockedExchangeAdd(&gBytesRead, rc);
InterlockedExchangeAdd(&gBytesReadLast, rc);
}
}
}
ExitThread(0);
return 0;
}
//
// Function: SendThread
//
// Description:
// This is the send thread started for each client connection.
// This thread waits for the semaphore to be signaled indicating that
// the receive thread has queued a buffer for sending.
//
DWORD WINAPI SendThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
BUFFER_OBJ *BuffObj=NULL;
int rc,
nleft,
idx;
// Retrieve the connection object
ConnObj = (CONNECTION_OBJ *)lpParam;
while (1)
{
// Wait for the receive thread to signal us
rc = WaitForSingleObject(ConnObj->hRecvSema, INFINITE);
if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
{
fprintf(stderr, "WaitForSingleObject failed: %d\n", GetLastError());
ExitProcess(-1);
}
// Retrieve the first buffer from this connection's queue
BuffObj = DequeueBufferObj(ConnObj);
//
// If the this receive by the receive thread indicated zero bytes then
// the connection has been gracefully closed. Otherwise, if an error
// was indicated then the connection was aborted.
//
if ((gProtocol == IPPROTO_TCP ) && ((BuffObj->buflen == 0) || (BuffObj->buflen == SOCKET_ERROR)))
{
FreeBufferObj(BuffObj);
BuffObj = NULL;
break;
}
if (gProtocol == IPPROTO_UDP)
{
// For UDP we send the packet back to the source address
rc = sendto(
ConnObj->s,
BuffObj->buf,
BuffObj->buflen,
0,
(SOCKADDR *)&BuffObj->addr,
BuffObj->addrlen
);
if (BuffObj->buflen == 0)
{
FreeBufferObj(BuffObj);
BuffObj = NULL;
break;
}
}
else if (gProtocol == IPPROTO_TCP)
{
// Otherwise send the buffer on the connection socket
nleft = BuffObj->buflen;
idx = 0;
while (nleft > 0)
{
rc = send(
ConnObj->s,
&BuffObj->buf[idx],
nleft,
0
);
if (rc == SOCKET_ERROR)
{
break;
}
else
{
nleft -= rc;
idx += rc;
}
}
}
if (rc == SOCKET_ERROR)
{
printf("SendThread: send(to) failed: %d\n", WSAGetLastError());
break;
}
else if (rc > 0)
{
// Increment the statistics
InterlockedExchangeAdd(&gBytesSent, rc);
InterlockedExchangeAdd(&gBytesSentLast, rc);
}
FreeBufferObj(BuffObj);
BuffObj = NULL;
}
// Close the connection's socket
closesocket(ConnObj->s);
FreeConnectionObj(ConnObj);
ExitThread(0);
return 0;
}
//
// Funtion: ServerListenThread
//
// Description:
// This function is spawned for each listening or receive thread
// depending on whether the server is started for UDP or TCP. In
// reality there will only be two server threads, one for IPv4
// and one for IPv6.
//
DWORD WINAPI ServerListenThread(LPVOID lpParam)
{
CONNECTION_OBJ *ConnObj=NULL;
HANDLE hThread = NULL;
SOCKET s;
int rc;
s = (SOCKET) lpParam;
if (gProtocol == IPPROTO_UDP)
{
// If we're UDP we don't have any "connections" to handle. we just have to
// receive UDP packets and send them back. Hence we only need 1 receiver
// thread and 1 sender thread for the whole thing.
//
ConnObj = GetConnectionObj(s);
hThread = CreateThread(NULL, 0, ReceiveThread, (LPVOID)ConnObj, 0, NULL);
if (hThread == NULL)
{
fprintf(stderr, "ServerListenThread: CreateThread failed: %d\n", GetLastError());
ExitThread(-1);
}
SendThread((LPVOID)ConnObj);
}
else if (gProtocol == IPPROTO_TCP)
{
SOCKADDR_STORAGE saAccept; // client address
SOCKET ns; // client socket
int acceptlen = sizeof(SOCKADDR_STORAGE);
rc = listen(s, 200);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
ExitThread(-1);
}
while (1)
{
// Wait for an incoming client connection
ns = accept(s, (SOCKADDR *)&saAccept, &acceptlen);
if (ns == INVALID_SOCKET)
{
fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
return -1;
}
InterlockedIncrement(&gConnectedClients);
/*
printf("Accepted connection from: ");
PrintAddress((SOCKADDR *)&saAccept, acceptlen);
printf("\n");
*/
// Allocate a connection object for this client
ConnObj = GetConnectionObj(ns);
// Create a receiver thread for this connection
hThread = CreateThread(NULL, 0, ReceiveThread, (LPVOID)ConnObj, 0, NULL);
if (hThread == NULL)
{
fprintf(stderr, "CreateThread failed: %d\n", GetLastError());
ExitThread(-1);
}
CloseHandle(hThread);
// Create a sender thread for this connection
hThread = CreateThread(NULL, 0, SendThread, (LPVOID)ConnObj, 0, NULL);
if (hThread == NULL)
{
fprintf(stderr, "CreateThread failed: %d\n", GetLastError());
ExitThread(-1);
}
CloseHandle(hThread);
}
}
closesocket(s);
ExitThread(0);
return 0;
}
//
// Function: main
//
// Description:
// This is the main program. It parses the command line and creates
// the main socket. For UDP this socket is used to receive datagrams.
// For TCP the socket is used to accept incoming client connections.
// Each client TCP connection is handed off to a worker thread which
// will receive any data on that connection until the connection is
// closed.
//
int __cdecl main(int argc, char **argv)
{
WSADATA wsd;
SOCKET s[MAX_LISTEN_SOCKETS];
HANDLE threads[MAX_LISTEN_SOCKETS];
int rc,
listencount=0,
i;
struct addrinfo *res=NULL,
*ptr=NULL;
ValidateArgs(argc, argv);
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
{
fprintf(stderr, "unable to load Winsock!\n");
return -1;
}
printf("Local address: %s; Port: %s; Family: %d\n",
gBindAddr, gBindPort, gAddressFamily);
res = ResolveAddress(gBindAddr, gBindPort, gAddressFamily, gSocketType, gProtocol);
if (res == NULL)
{
fprintf(stderr, "ResolveAddress failed to return any addresses!\n");
return -1;
}
// For each local address returned, create a listening/receiving socket
ptr = res;
while (ptr)
{
if (listencount > MAX_LISTEN_SOCKETS)
{
fprintf(stderr, "Exceeded maximum listening sockets allowed\n");
return -1;
}
PrintAddress(ptr->ai_addr, ptr->ai_addrlen); printf("\n");
// create the socket
s[listencount] = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (s[listencount] == INVALID_SOCKET)
{
fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
return -1;
}
// bind the socket to a local address and port
rc = bind(s[listencount], ptr->ai_addr, ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
return -1;
}
// Create a listen thread for each local address to listen on
threads[listencount] = CreateThread(
NULL,
0,
ServerListenThread,
(LPVOID)s[listencount],
0,
NULL
);
if (threads[listencount] == NULL)
{
fprintf(stderr, "CreateThread failed: %d\n", GetLastError());
return -1;
}
listencount++;
ptr = ptr->ai_next;
}
gStartTime = gStartTimeLast = GetTickCount();
// free the addrinfo structure for the 'bind' address
freeaddrinfo(res);
while (1)
{
// Wait for the listening threads to exit, also print out statistics
// when the wait times out
rc = WaitForMultipleObjects(listencount, threads, TRUE, 5000);
if (rc == WAIT_FAILED)
{
fprintf(stderr, "WaitForMultipleObjects failed: %d\n", GetLastError());
return -1;
}
else if (rc == WAIT_TIMEOUT)
{
ULONG bps, tick, elapsed;
tick = GetTickCount();
elapsed = (tick - gStartTime) / 1000;
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;
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);
printf("Current Connections: %lu\n", gConnectedClients);
gStartTimeLast = tick;
}
else
{
break;
}
}
// Close the thread handles opened
for (i=0; i < listencount ;i++)
{
CloseHandle(threads[i]);
}
WSACleanup();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -