📄 wsnbsvr.cpp
字号:
// Module Name: wsnbsvr.cpp
//
// Description:
// This sample illustrates creating a Winsock server using
// the AF_NETBIOS address family. The server creates a listening
// socket for each LANA number of the given socket type.
// For datagrams, each listening socket waits for incoming data.
// For connection-oriented communication, the server waits
// for client connections at which point a thread is created
// to service the connection.
//
// Compile:
// cl /c wsnbdef.cpp
// cl -o wsnbsvr wsnbsvr.cpp wsnbdef.obj ws2_32.lib
//
// Command Line Parameters/Options:
// wsnbsvr [-n str] [-p int] [-l int] [-t char] [-c int] [-b int]
// -n NAME Our NetBIOS name\n");
// -p PORT The 16th byte qualifier of our name
// -l LANA Specifies to listen on this LANA only
// By default listen on all LANAs
// -t TYPE Specifies datagram (d) or seqpacket (s)
// -c COUNT Number of types to receive per client
// -b SIZE Size of buffer to receive
//
#include <winsock2.h>
#include <wsnetbs.h>
#include <stdio.h>
#include <stdlib.h>
//
// A couple common definitions used between client and server
//
#include "wsnbdef.h"
//
// Global variables for the name of our server and its
// 16th byte qualifier.
//
char szServerName[NETBIOS_NAME_LENGTH]; // Our NetBIOS name
int iPort, // Our 16th byte
iLana, // LANA to listen on
iSocketType=SOCK_SEQPACKET; // Socket type
DWORD dwCount=DEFAULT_COUNT, // How many packets
dwSize=MAX_BUFFER; // Receive buffer size
BOOL bOneLana=FALSE; // Listen on one lana only
//
// Function: usage
//
// Description:
// Print out usage information.
//
void usage()
{
printf("usage: wsnbsvr -n str -p int -l int -t char -c int -b int\n");
printf(" -n NAME Our NetBIOS name\n");
printf(" -p PORT The 16th byte qualifier of our name\n");
printf(" -l LANA Specifies to listen on this LANA only\n");
printf(" By default listen on all LANAs\n");
printf(" -t TYPE Specifies datagram (d) or seqpacket (s)\n");
printf(" -c COUNT Number of types to receive per client\n");
printf(" -b SIZE Size of buffer to receive\n");
ExitProcess(1);
}
//
// Function: ValidateArgs
//
// Description
// Parse the argument list for our NetBIOS name and whether
// we want to operate on all LANAs or just one.
//
void ValidateArgs(int argc, char **argv)
{
int i;
if (argc > 1)
{
for (i = 1; i < argc; i++)
{
if ( (argv[i][0] == '-') || (argv[i][0] == '/') )
{
switch (tolower(argv[i][1]) )
{
case '?':
usage();
break;
case 'n': // use a unique name
if (i+1 < argc)
{
strncpy(szServerName,argv[i+1],NETBIOS_NAME_LENGTH);
if (0 != strlen(szServerName)) ++i;
}
break;
case 'p': // set the 16th byte
if (i+1 < argc)
{
iPort = atoi(argv[i+1]);
++i;
}
break;
case 'l': // listen on one lana only
if (i+1 < argc)
{
bOneLana = TRUE;
iLana = atoi(argv[i+1]);
++i;
}
break;
case 't': // datagram or stream socket?
if (i+1 < argc)
{
if ('s' == tolower(argv[i+1][0]))
iSocketType = SOCK_SEQPACKET;
else if ('d' == tolower(argv[i+1][0]))
iSocketType = SOCK_DGRAM;
else
usage();
++i;
}
break;
case 'c': // number of messages to send
if (i+1 < argc)
{
dwCount = atol(argv[i+1]);
++i;
}
break;
case 'b': // size of send buffer
if (i+1 < argc)
{
dwSize = (atol(argv[i+1]) > MAX_BUFFER ? MAX_BUFFER : atol(argv[i+1]));
++i;
}
break;
default:
usage();
break;
}
}
}
}
return;
}
//
// Function: ClientThread
//
// Description:
// This thread is spawned for each incoming client connection to
// handle the echo server responsiblities.
//
DWORD WINAPI ClientThread(LPVOID lpParam)
{
SOCKET sock = (SOCKET)lpParam;
char szRecvBuff[MAX_BUFFER];
DWORD dwRet,
dwErr;
unsigned long iOptVal = 1L;
// Make the client connection non-blocking
//
if (ioctlsocket(sock, FIONBIO, &iOptVal) == SOCKET_ERROR)
{
printf("ioctlsocket(FIONBIO) failed: %d\n", WSAGetLastError());
}
// In a loop read and write the data from and to the client
//
while (1)
{
dwRet = recv(sock, szRecvBuff, MAX_BUFFER, 0);
if (dwRet == 0)
{
printf("Graceful close\n");
return 0;
} else if (dwRet == SOCKET_ERROR)
{
// If we get a WSAEWOULDBLOCK just keep going
//
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
continue;
else if (dwErr == WSAECONNRESET)
{
printf("Client aborted connection...\n");
return 0;
} else
{
printf("recv() failed: %d\n", dwErr);
return 1;
}
}
szRecvBuff[dwRet] = 0;
printf("Read %d bytes\n", dwRet);
while (1)
{
dwRet = send(sock, szRecvBuff, dwRet, 0);
if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
continue;
else if (dwErr == WSAECONNRESET)
break;
printf("send() failed: %d\n", dwErr);
return 1;
}
break;
}
}
closesocket(sock);
return 0;
}
//
// Function: main
//
// Description:
// Parse the command line parameters, load the Winsock library,
// enumerate the LANAs, and listen according to what is specified
// by the command line. By default, a listen will be posted on
// every available LANA. Once a client connection is made, spawn
// a thread to handle that connection.
//
int main(int argc, char **argv)
{
WSADATA wsd;
HANDLE hThread;
DWORD dwThreadId,
dwNumProtocols,
dwIndex,
dwErr,
i;
int iLastByte,
addrlen = sizeof(SOCKADDR_NB),
iEvents;
WSAPROTOCOL_INFO *wsapi=NULL;
SOCKET *sockListen=NULL, // array of listening sockets
sockClient;
WSAEVENT *hEvents=NULL; // one event for each LANA
SOCKADDR_NB nbaddr, // our NetBIOS address
nbclient; // client's NetBIOS address
BOOL bDone;
// Parse command line and load Winsock library
//
ValidateArgs(argc, argv);
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("Unable to load Winsock!\n");
return 1;
}
// If we are listening on all LANAs enumerate them
//
if (!bOneLana)
{
if (FindProtocol(&wsapi, &dwNumProtocols) != TRUE)
{
printf("Unable to find correct protocol!\n");
return 1;
}
CullInvalidProviders(wsapi, &dwNumProtocols);
if (dwNumProtocols == 0)
{
printf("No NetBIOS capable providers found\n");
return 1;
}
}
else
{
dwNumProtocols = 1;
}
SET_NETBIOS_SOCKADDR(&nbaddr, NETBIOS_UNIQUE_NAME, szServerName,
iPort);
//
// Allocate a SOCKET handle for each LANA we are going to listen on
//
sockListen = (SOCKET *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(SOCKET) * dwNumProtocols);
if (sockListen == NULL)
{
printf("out of memory\n");
return 1;
}
//
// Allocate an event handle for each LANA we are going to listen on
//
hEvents = (WSAEVENT *) GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(WSAEVENT) * dwNumProtocols);
if (hEvents == NULL)
{
printf("out of memory\n");
return 1;
}
// For each service provider create a ServerThread except for
// the last provider which we'll start in this main thread.
//
for (i=0; i < dwNumProtocols ;i++)
{
if (!bOneLana)
printf("Transport: '%s'\n", wsapi[i].szProtocol);
else
printf("Transport: LANA: %d\n", iLana);
hEvents[i] = WSACreateEvent();
if (hEvents[i] == NULL)
{
printf("WSACreateEvent failed: %d\n", WSAGetLastError());
continue;
}
// Create socket(s)
//
if (!bOneLana)
sockListen[i] = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &wsapi[i], 0, WSA_FLAG_OVERLAPPED);
else
sockListen[i] = WSASocket(AF_NETBIOS, SOCK_SEQPACKET, -iLana,
NULL, 0, WSA_FLAG_OVERLAPPED);
if (sockListen[i] == SOCKET_ERROR)
{
printf("WSASocket failed: %d\n", WSAGetLastError());
continue;
}
// Bind and listen each socket to our server name
//
if (bind(sockListen[i], (SOCKADDR *)&nbaddr,
sizeof(nbaddr)) == SOCKET_ERROR)
{
printf("bind() failed: %d\n", WSAGetLastError());
return 1;
}
listen(sockListen[i], 10);
//
// We're only interested in FD_ACCEPT events for our server
// sockets
//
if (iSocketType == SOCK_SEQPACKET)
iEvents = FD_ACCEPT;
else
iEvents = FD_READ;
if (WSAEventSelect(sockListen[i], hEvents[i], iEvents) ==
SOCKET_ERROR)
{
printf("WSAEventSelect failed: %d\n", WSAGetLastError());
return 1;
}
}
bDone = FALSE;
while (!bDone)
{
// Wait until a client connection is pending
//
dwIndex = WSAWaitForMultipleEvents(dwNumProtocols, hEvents, FALSE,
WSA_INFINITE, FALSE);
if (dwIndex == WSA_WAIT_FAILED)
{
printf("WSAWaitForEvents failed: %d\n", WSAGetLastError());
return 1;
}
addrlen = sizeof(nbclient);
if (iSocketType == SOCK_SEQPACKET)
{
sockClient = accept(sockListen[dwIndex], (SOCKADDR *)&nbclient,
&addrlen);
if (sockClient == INVALID_SOCKET)
{
if ((dwErr = WSAGetLastError()) != WSAEWOULDBLOCK)
{
printf("accept() failed: %d\n", dwErr);
return 1;
} else
continue;
}
// Print out the client name who connected
//
iLastByte = nbclient.snb_name[NETBIOS_NAME_LENGTH-1];
nbclient.snb_name[NETBIOS_NAME_LENGTH-1];
printf("Client '%s<%02d>' connected\n", nbclient.snb_name, iLastByte);
//
// Create a thread to handle the connection
//
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)sockClient,
0, &dwThreadId);
if (hThread == NULL)
{
printf("CreateThread() failed: %d\n", GetLastError());
return 1;
}
CloseHandle(hThread);
sockClient = INVALID_SOCKET;
} else
{
char recvBuff[MAX_BUFFER];
DWORD dwRet;
dwRet = recvfrom(sockListen[dwIndex], recvBuff, MAX_BUFFER, 0,
(SOCKADDR *)&nbclient, &addrlen);
if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
continue;
printf("recvfrom() failed: %d\n", dwErr);
return 1;
}
iLastByte = nbclient.snb_name[NETBIOS_NAME_LENGTH-1];
nbclient.snb_name[NETBIOS_NAME_LENGTH-1];
printf("Read %d bytes from '%s'<%02d>\n", dwRet, nbclient.snb_name,
iLastByte);
dwRet = sendto(sockListen[dwIndex], recvBuff, dwRet, 0,
(SOCKADDR *)&nbclient, sizeof(nbclient));
if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
continue;
printf("sendto() failed: %d\n", dwErr);
return 1;
}
printf("Wrote %d bytes\n", dwRet);
}
WSAResetEvent(hEvents[dwIndex]);
}
// Clean up things
//
for (i=0; i < dwNumProtocols ;i++)
{
closesocket(sockListen[i]);
WSACloseEvent(hEvents[i]);
}
GlobalFree(wsapi);
GlobalFree(hEvents);
GlobalFree(sockListen);
WSACleanup();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -