📄 eventserver.cpp
字号:
}
}
if (nevents.lNetworkEvents & FD_CLOSE)
{
// Check for close error
if (nevents.iErrorCode[FD_CLOSE_BIT] == 0)
{
// Socket has been indicated as closing so make sure all the data
// has been read
while (1)
{
rc = ReceivePendingData(sock);
if (rc == -1)
{
RemoveSocketObj(thread, sock);
FreeSocketObj(sock);
return SOCKET_ERROR;
}
else if (rc != 0)
{
continue;
}
else
{
break;
}
}
// See if there is any data pending, if so try to send it
rc = SendPendingData(sock);
if (rc == -1)
{
RemoveSocketObj(thread, sock);
FreeSocketObj(sock);
return SOCKET_ERROR;
}
}
else
{
fprintf(stderr, "HandleIo: FD_CLOSE error %d\n",
nevents.iErrorCode[FD_CLOSE_BIT]);
RemoveSocketObj(thread, sock);
FreeSocketObj(sock);
return SOCKET_ERROR;
}
}
return NO_ERROR;
}
void RenumberThreadArray(THREAD_OBJ *thread)
{
SOCKET_OBJ *sptr=NULL;
int i;
EnterCriticalSection(&thread->ThreadCritSec);
i = 0;
sptr = thread->SocketList;
while (sptr)
{
thread->Handles[i+1] = sptr->event;
i++;
sptr = sptr->next;
}
LeaveCriticalSection(&thread->ThreadCritSec);
}
//
// Function: ChildThread
//
// Description:
// This is the child thread that handles socket connections. Each thread
// can only wait on a maximum of 63 sockets. The main thread will assign
// each client connection to one of the child threads. If there is no
// thread to handle the socket, a new thread is created to handle the
// connection.
//
DWORD WINAPI ChildThread(LPVOID lpParam)
{
THREAD_OBJ *thread=NULL;
SOCKET_OBJ *sptr=NULL,
*sockobj=NULL;
int index,
rc,
i;
thread = (THREAD_OBJ *)lpParam;
while (1)
{
rc = WaitForMultipleObjects(
thread->SocketCount + 1,
thread->Handles,
FALSE,
INFINITE
);
if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
{
fprintf(stderr, "ChildThread: WaitForMultipleObjects failed: %d\n", GetLastError());
break;
}
else
{
// Multiple events may be signaled at one time so check each
// event to see if its signaled
//
for(i=0; i < thread->SocketCount + 1 ;i++)
{
rc = WaitForSingleObject(thread->Handles[i], 0);
if (rc == WAIT_FAILED)
{
fprintf(stderr, "ChildThread: WaitForSingleObject failed: %d\n", GetLastError());
ExitThread(-1);
}
else if (rc == WAIT_TIMEOUT)
{
// This event isn't signaled, continue to the next one
continue;
}
index = i;
if (index == 0)
{
// If index 0 is signaled then rebuild the array of event
// handles to wait on
WSAResetEvent(thread->Handles[index]);
RenumberThreadArray(thread);
i = 1;
}
else
{
// Otherwise, its an event associated with a socket that
// was signaled. Handle the IO on that socket.
//
sockobj = FindSocketObj(thread, index-1);
if (sockobj != NULL)
{
if (HandleIo(thread, sockobj) == SOCKET_ERROR)
{
RenumberThreadArray(thread);
}
}
else
{
printf("Unable to find socket object!\n");
}
}
}
}
}
ExitThread(0);
return 0;
}
//
// Function: AssignToFreeThread
//
// Description:
// This routine assigns a socket connection to an available child
// thread to handle any IO on it. If no threads are available, a
// new thread is spawned to handle the connection.
//
void AssignToFreeThread(SOCKET_OBJ *sock)
{
THREAD_OBJ *thread=NULL;
thread = gChildThreads;
while (thread)
{
// If this routine returns something other than SOCKET_ERROR
// that it was successfully assigned to a child thread.
if (InsertSocketObj(thread, sock) != SOCKET_ERROR)
break;
thread = thread->next;
}
if (thread == NULL)
{
// No thread was found to assign the client socket to, create a new thread
//
printf("Creating new thread object\n");
thread = GetThreadObj();
thread->Thread = CreateThread(NULL, 0, ChildThread, (LPVOID)thread, 0, NULL);
if (thread->Thread == NULL)
{
fprintf(stderr, "AssignToFreeThread: CreateThread failed: %d\n", GetLastError());
ExitProcess(-1);
}
InsertSocketObj(thread, sock);
// Insert the thread the list of threads
if (gChildThreads == NULL)
{
gChildThreads = thread;
}
else
{
thread->next = gChildThreads;
gChildThreads = thread;
}
gChildThreadsCount++;
}
// signal child thread to rebuild the event list
WSASetEvent(thread->Event);
return;
}
//
// 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;
THREAD_OBJ *thread=NULL;
SOCKET_OBJ *sockobj=NULL,
*newsock=NULL;
int index,
rc;
struct addrinfo *res=NULL,
*ptr=NULL;
// Validate the command line
ValidateArgs(argc, argv);
// Load Winsock
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;
}
thread = GetThreadObj();
// For each local address returned, create a listening/receiving socket
ptr = res;
while (ptr)
{
PrintAddress(ptr->ai_addr, ptr->ai_addrlen); printf("\n");
sockobj = GetSocketObj(INVALID_SOCKET, (gProtocol == IPPROTO_TCP) ? TRUE : FALSE);
// create the socket
sockobj->s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (sockobj->s == INVALID_SOCKET)
{
fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
return -1;
}
InsertSocketObj(thread, sockobj);
// bind the socket to a local address and port
rc = bind(sockobj->s, ptr->ai_addr, ptr->ai_addrlen);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
return -1;
}
if (gProtocol == IPPROTO_TCP)
{
rc = listen(sockobj->s, 200);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
return -1;
}
// Register events on the socket
rc = WSAEventSelect(
sockobj->s,
sockobj->event,
FD_ACCEPT | FD_CLOSE
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
return -1;
}
}
else
{
// Register events on the socket
rc = WSAEventSelect(
sockobj->s,
sockobj->event,
FD_READ | FD_WRITE | FD_CLOSE
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
return -1;
}
}
ptr = ptr->ai_next;
}
// free the addrinfo structure for the 'bind' address
freeaddrinfo(res);
gStartTime = gStartTimeLast = GetTickCount();
while (1)
{
rc = WaitForMultipleObjects(
thread->SocketCount + 1,
thread->Handles,
FALSE,
5000
);
if (rc == WAIT_FAILED)
{
fprintf(stderr, "WaitForMultipleObjects failed: %d\n", GetLastError());
break;
}
else if (rc == WAIT_TIMEOUT)
{
PrintStatistics();
}
else
{
index = rc - WAIT_OBJECT_0;
sockobj = FindSocketObj(thread, index-1);
if (gProtocol == IPPROTO_TCP)
{
SOCKADDR_STORAGE sa;
WSANETWORKEVENTS ne;
SOCKET sc;
int salen;
rc = WSAEnumNetworkEvents(
sockobj->s,
thread->Handles[index],
&ne
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "WSAEnumNetworkEvents failed: %d\n", WSAGetLastError());
break;
}
while (1)
{
sc = INVALID_SOCKET;
salen = sizeof(sa);
//
// For TCP, accept the connection and hand off the client socket
// to a worker thread
//
sc = accept(
sockobj->s,
(SOCKADDR *)&sa,
&salen
);
if ((sc == INVALID_SOCKET) && (WSAGetLastError() != WSAEWOULDBLOCK))
{
fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
break;
}
else if (sc != INVALID_SOCKET)
{
newsock = GetSocketObj(INVALID_SOCKET, FALSE);
// Copy address information
memcpy(&newsock->addr, &sa, salen);
newsock->addrlen = salen;
newsock->s = sc;
InterlockedIncrement(&gTotalConnections);
InterlockedIncrement(&gCurrentConnections);
/*
printf("Accepted connection from: ");
PrintAddress((SOCKADDR *)&newsock->addr, newsock->addrlen);
printf("\n");
*/
// Register for read, write and close on the client socket
rc = WSAEventSelect(
newsock->s,
newsock->event,
FD_READ | FD_WRITE | FD_CLOSE
);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
break;
}
AssignToFreeThread(newsock);
}
else
{
// Failed with WSAEWOULDBLOCK -- just continue
break;
}
}
}
else
{
// For UDP all we have to do is handle events on the main
// threads.
if (HandleIo(thread, sockobj) == SOCKET_ERROR)
{
RenumberThreadArray(thread);
}
}
}
}
WSACleanup();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -