📄 wsnbclnt.cpp
字号:
// Module Name: wsnbclnt.cpp
//
// Description:
// This sample illustrates how to use the AF_NETBIOS protocol family
// from a Winsock application. This particular sample is a client
// that communicates with to the server (wsnbsvr.c) sample.
//
// Compile:
// cl -o wsnbclnt wsnbclnt.cpp ws2_32.lib
//
// Command Line Parameters/Options:
// wsnbclnt.exe options
//
// -n NAME - Server's Netbios name
// -p PORT - Use this integer value as the 16th byte of server name
// -l LANA - Attempt a connection on this LANA number only, the
// default behavior is to attempt a connection on all
// LANA numbers
// -t TYPE - Specifies datagram (d) or seqpacket (s)
// -c COUNT - Number of types to send the message
// -b SIZE - Size of buffer to send
//
#include <winsock2.h>
#include <wsnetbs.h>
#include <stdio.h>
#include <stdlib.h>
//
// A couple common definitions used between client and server
//
#include "wsnbdef.h"
char szServerName[NETBIOS_NAME_LENGTH]; // Our NetBIOS name
int iPort, // Our 16th byte
iLana, // LANA to connect on
iSocketType=SOCK_SEQPACKET; // Datagram or stream?
DWORD dwCount=DEFAULT_COUNT, // How many packets
dwSize=MAX_BUFFER; // Size of buffer to send
BOOL bOneLana=FALSE; // Connect on one LANA
//
// Function: usage
//
// Description:
// Print out usage information.
//
void usage()
{
printf("usage: wsnbclnt -n str -p int -l int -t char\n");
printf(" -n NAME Our NetBIOS name\n");
printf(" -p PORT The 16th byte qualifier of our name\n");
printf(" -l LANA Specifies to connect on this LANA only\n");
printf(" By default attempt connection on all LANAs\n");
printf(" -t TYPE Specifies datagram (d) or seqpacket (s)\n");
printf(" -c COUNT Number of types to send the message\n");
printf(" -b SIZE Size of buffer to send\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': // connect on one lana only
if (i+1 < argc)
{
bOneLana = TRUE;
if (strlen(argv[i+1]) > 3)
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': // num types to send message
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: main
//
// Description:
// This function parses the command line arguments, loads the
// Winsock library, and connects to a server. By default, a
// connection is attempted on all available LANA numbers. The
// first one to succeed is used and the others are cancelled.
//
int main(int argc, char **argv)
{
WSADATA wsd;
SOCKET *socks=NULL; // array of socket handles
WSAEVENT *hEvents=NULL; // events for each socket
SOCKADDR_NB nbaddr; // NetBIOS addr of server
WSAPROTOCOL_INFO *wsapi=NULL;
DWORD dwRet,
dwNumProtocols,
dwIndex,
dwErr,
i;
char szMessage[MAX_BUFFER]; // Data buffer
unsigned long iOptVal;
struct fd_set fdread;
// Validate arguments
//
ValidateArgs(argc, argv);
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("Unable to load Winsock!\n");
return 1;
}
// If we're connecting on all LANAs enumerate all AF_NETBIOS
// protocols; if not we can just specify the LANA we want
// when creating the socket.
//
if (bOneLana == FALSE)
{
// This function will return an array of WSAPROTOCOL_INFO
// structures that match our socket type
//
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;
}
// Setup the NetBIOS address name
//
SET_NETBIOS_SOCKADDR(&nbaddr, NETBIOS_UNIQUE_NAME, szServerName,
iPort);
//
// Allocate some global structures.
// socks : array of SOCKET handles for each transport we connect on
// hEvents : array of WSAEVENT handles for event notification
//
socks = (SOCKET *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(SOCKET) * dwNumProtocols);
if (socks == NULL)
{
printf("out of memory\n");
return 1;
}
hEvents = (WSAEVENT *)GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT,
sizeof(WSAEVENT) * dwNumProtocols);
if (hEvents == NULL)
{
printf("out of memory\n");
return 1;
}
// For each LANA, create a WSAEVENT, create the SOCKET, and
// register it for what events we want to receive.
//
for (i=0; i < dwNumProtocols ;i++)
{
if (bOneLana)
printf("Transport LANA: %d\n", iLana);
else
printf("Transport: '%s'\n", wsapi[i].szProtocol);
hEvents[i] = WSACreateEvent();
if (hEvents[i] == NULL)
{
printf("WSACreateEvent failed: %d\n", WSAGetLastError());
return 1;
}
if (bOneLana == FALSE)
socks[i] = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO, &wsapi[i], 0, WSA_FLAG_OVERLAPPED);
else
socks[i] = WSASocket(AF_NETBIOS, SOCK_SEQPACKET, -iLana, NULL,
0, WSA_FLAG_OVERLAPPED);
if (socks[i] == INVALID_SOCKET)
{
printf("socket() failed: %d\n", WSAGetLastError());
return 1;
}
if (WSAConnect(socks[i], (SOCKADDR *)&nbaddr, sizeof(nbaddr),
NULL, NULL, NULL, NULL) == SOCKET_ERROR)
{
printf("WSACOnnect failed: %d\n", WSAGetLastError());
continue;
}
if (WSAEventSelect(socks[i], hEvents[i], FD_CONNECT) ==
SOCKET_ERROR)
{
printf("WSAEventSelect failed: %d\n", WSAGetLastError());
return 1;
}
}
// Wait for one of the connects to succeed
//
dwIndex = WSAWaitForMultipleEvents(dwNumProtocols, hEvents, FALSE,
WSA_INFINITE, FALSE);
if (dwIndex == WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents failed: %d\n", WSAGetLastError());
return 1;
}
// Close the sockets of all other pending connections other than the
// one that completed first
//
dwIndex -= WAIT_OBJECT_0;
for (i=0; i < dwNumProtocols ;i++)
{
if (i != dwIndex)
closesocket(socks[i]);
}
// Put the socket in non-blocking mode
//
iOptVal = 1L;
if (ioctlsocket(socks[dwIndex], FIONBIO, &iOptVal) == SOCKET_ERROR)
{
printf("ioctlsocket(FIONBIO) failed: %d\n", WSAGetLastError());
}
memset(szMessage, 'a', dwSize);
for (i=0; i < dwCount ;i++)
{
// Send the message to the server
//
dwRet = send(socks[dwIndex], szMessage, dwSize, 0);
if (dwRet == 0)
{
printf("graceful close\n");
closesocket(socks[dwIndex]);
return 0;
} else if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
{
i--;
continue;
} else
{
printf("send failed: %d\n", dwErr);
return 1;
}
}
printf("Wrote %d bytes\n", dwRet);
//
// Wait until the server echoes the data back. This really doesn't
// matter when using SOCK_SEQPACKET, but if we're using SOCK_DGRAM
// then our recv() would fail with WSAEWOULDBLOCK and we'd skip
// the returned data (as the server might not have sent it yet)
//
FD_ZERO(&fdread);
FD_SET(socks[dwIndex], &fdread);
select(0, &fdread, NULL, NULL, NULL);
//
// Read the message back
//
dwRet = recv(socks[dwIndex], szMessage, MAX_BUFFER, 0);
if (dwRet == 0)
{
printf("graceful close\n");
closesocket(socks[dwIndex]);
return 0;
} else if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
{
i--;
continue;
} else
{
printf("recv() failed: %d\n", dwErr);
return 1;
}
}
printf("Read %d bytes\n", dwRet);
}
closesocket(socks[dwIndex]);
for (i=0; i < dwNumProtocols ;i++)
WSACloseEvent(hEvents[i]);
GlobalFree(wsapi);
GlobalFree(socks);
GlobalFree(hEvents);
WSACleanup();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -