📄 nbserver.cpp
字号:
&buffobj->addrlen
);
}
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() != WSAEWOULDBLOCK)
{
// Socket connection has failed, close the socket
fprintf(stderr, "recv(from) failed: %d\n", WSAGetLastError());
closesocket(sockobj->s);
ret = -1;
}
FreeBufferObj(buffobj);
}
else if (rc == 0)
{
// Graceful close
if (gProtocol == IPPROTO_TCP)
{
FreeBufferObj(buffobj);
}
else
{
buffobj->buflen = 0;
EnqueueBufferObj(sockobj, buffobj, FALSE);
}
sockobj->closing = TRUE;
if (sockobj->pending == NULL)
{
// If no sends are pending, close the socket for good
closesocket(sockobj->s);
ret = -1;
}
}
else
{
// Read data, updated the counters and enqueue the buffer for sending
gBytesRead += rc;
gBytesReadLast += rc;
buffobj->buflen = rc;
EnqueueBufferObj(sockobj, buffobj, FALSE);
}
return ret;
}
//
// Function: SendPendingData
//
// Description:
// Send any data pending on the socket. This routine goes through the
// queued buffer objects within the socket object and attempts to
// send all of them. If the send fails with WSAEWOULDBLOCK, put the
// remaining buffer back in the queue (at the front) for sending
// later when select indicates sends can be made. This routine returns
// -1 to indicate that an error has occured on the socket and the
// calling routine should remove the socket structure; otherwise, zero
// is returned.
//
int SendPendingData(SOCKET_OBJ *sock)
{
BUFFER_OBJ *bufobj=NULL;
BOOL breakouter;
int nleft,
idx,
ret,
rc;
// Attempt to dequeue all the buffer objects on the socket
ret = 0;
while (bufobj = DequeueBufferObj(sock))
{
if (gProtocol == IPPROTO_TCP)
{
breakouter = FALSE;
nleft = bufobj->buflen;
idx = 0;
// In the event not all the data was sent we need to increment
// through the buffer. This only needs to be done for stream
// sockets since UDP is datagram and its all or nothing for that.
while (nleft)
{
rc = send(
sock->s,
&bufobj->buf[idx],
nleft,
0
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
BUFFER_OBJ *newbuf=NULL;
// Copy the unsent portion of the buffer and put it back
// at the head of the send queue
newbuf = GetBufferObj(nleft);
memcpy(newbuf->buf, &bufobj->buf[idx], nleft);
EnqueueBufferObj(sock, newbuf, TRUE);
}
else
{
// The connection was broken, indicate failure
ret = -1;
}
breakouter = TRUE;
break;
}
else
{
// Update the stastics and increment the send counters
gBytesSent += rc;
gBytesSentLast += rc;
nleft -= rc;
idx += 0;
}
}
FreeBufferObj(bufobj);
if (breakouter)
break;
}
else
{
rc = sendto(
sock->s,
bufobj->buf,
bufobj->buflen,
0,
(SOCKADDR *)&bufobj->addr,
bufobj->addrlen
);
if (rc == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
// If the send couldn't be made, put the buffer
// back at the head of the queue
EnqueueBufferObj(sock, bufobj, TRUE);
ret = 0;
}
else
{
// Socket error occured so indicate the error to the caller
ret = -1;
}
break;
}
else
{
FreeBufferObj(bufobj);
}
}
}
// If no more sends are pending and the socket was marked as closing (the
// receiver got zero bytes) then close the socket and indicate to the caller
// to remove the socket structure.
if ((sock->pending == NULL) && (sock->closing))
{
closesocket(sock->s);
ret = -1;
printf("Closing connection\n");
}
return ret;
}
//
// 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("Current Connections: %lu\n", gCurrentConnections);
InterlockedExchange(&gBytesSentLast, 0);
InterlockedExchange(&gBytesReadLast, 0);
gStartTimeLast = tick;
}
//
// 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;
SOCKET_OBJ *sockobj=NULL,
*sptr=NULL,
*tmp=NULL;
ULONG lastprint=0;
int rc;
struct fd_set fdread,
fdwrite,
fdexcept;
struct timeval timeout;
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)
{
PrintAddress(ptr->ai_addr, ptr->ai_addrlen); printf("\n");
// create the socket
s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (s == INVALID_SOCKET)
{
fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
return -1;
}
sockobj = GetSocketObj(s, (gProtocol == IPPROTO_TCP) ? TRUE : FALSE);
InsertSocketObj(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;
}
}
ptr = ptr->ai_next;
}
// free the addrinfo structure for the 'bind' address
freeaddrinfo(res);
gStartTime = gStartTimeLast = lastprint = GetTickCount();
while (1)
{
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcept);
sptr = gSocketList;
// Set each socket in the FD_SET structures
while (sptr)
{
FD_SET(sptr->s, &fdread);
FD_SET(sptr->s, &fdwrite);
FD_SET(sptr->s, &fdexcept);
sptr = sptr->next;
}
timeout.tv_sec = 5;
timeout.tv_usec = 0;
rc = select(0, &fdread, &fdwrite, &fdexcept, &timeout);
if (rc == SOCKET_ERROR)
{
fprintf(stderr, "select failed: %d\n", WSAGetLastError());
return -1;
}
else if (rc == 0)
{
// timeout
PrintStatistics();
}
else
{
// Go through all the socket and see if they're present in the
// fd_set structures.
sptr = gSocketList;
while (sptr)
{
if (FD_ISSET(sptr->s, &fdread))
{
if (sptr->listening)
{
// Read is indicated on a listening socket, accept the connection
sockobj = GetSocketObj(INVALID_SOCKET, FALSE);
s = accept(sptr->s, (SOCKADDR *)&sockobj->addr, &sockobj->addrlen);
if (s == INVALID_SOCKET)
{
fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
return -1;
}
InterlockedIncrement(&gCurrentConnections);
sockobj->s = s;
/*
printf("Accepted connection from: ");
PrintAddress((SOCKADDR *)&sockobj->addr, sockobj->addrlen);
printf("\n");
*/
InsertSocketObj(sockobj);
}
else
{
// Read is indicated on a client socket, receive data
if (ReceivePendingData(sptr) != 0)
{
printf("ReceivePendingData indicated to remove obj\n");
tmp = sptr;
sptr = sptr->next;
RemoveSocketObj(tmp);
FreeSocketObj(tmp);
// At the end of the list
if (sptr == NULL)
continue;
}
// Attempt to send pending data
if (SendPendingData(sptr) != 0)
{
tmp = sptr;
sptr = sptr->next;
RemoveSocketObj(tmp);
FreeSocketObj(tmp);
// At the end of the list
if (sptr == NULL)
continue;
}
}
}
if (FD_ISSET(sptr->s, &fdwrite))
{
// Write is indicated so attempt to send the pending data
if (SendPendingData(sptr) != 0)
{
tmp = sptr;
sptr = sptr->next;
RemoveSocketObj(tmp);
FreeSocketObj(tmp);
// At the end of the list
if (sptr == NULL)
continue;
}
}
if (FD_ISSET(sptr->s, &fdexcept))
{
// Not handling OOB data so just close the connection
tmp = sptr;
sptr = sptr->next;
RemoveSocketObj(tmp);
FreeSocketObj(tmp);
// At the end of the list
if (sptr == NULL)
continue;
}
sptr = sptr->next;
}
}
// See if we should print statistics
if ( (GetTickCount() - lastprint) > 5000)
{
PrintStatistics();
lastprint = GetTickCount();
}
}
WSACleanup();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -