< NetBIOS Server Examples | Winsock2 Supported Protocols Main | AppleTalk Protocol >
What do we have in this chapter 4 part 6?
|
The Netbios Client Program
Create a new empty Win32 console mode application and add the project/solution name.
|
Add the Netbios client source code.
// 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 (NetbiosServer) sample
//
// Command Line Parameters/Options:
// NetbiosClient 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>
// Common definitions shared by 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.
int usage()
{
printf("Usage: NetbiosClient -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 (this is client LANA lor!)\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");
printf("Example: NetbiosClient -n MIKEBLUR -p 7172 -l 3 -t s -c 5 -b 64\n");
return 0;
}
// Function: ValidateArgs
// Description
// Parse the argument list for our NetBIOS name and whether
// we want to operate on all LANAs or just one
int 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_s(szServerName,sizeof(szServerName),argv[i+1],NETBIOS_NAME_LENGTH);
if (strlen(szServerName) != 0)
++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;
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 0;
}
// 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;
int j;
// Validate arguments
if(argc < 2)
{
usage();
return 1;
}
else
ValidateArgs(argc, argv);
// These all just another verification!
printf("iLana = %d\n", iLana);
printf("szServerName = %s\n", szServerName);
printf("iPort = %d\n", iPort);
printf("iSocketType = %d\n", iSocketType);
printf("dwCount = %d\n", dwCount);
printf("dwSize = %d\n", dwSize);
printf("\n");
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("Unable to load Winsock!\n");
return 1;
}
else
printf("WSAStartup() is OK!\n");
// 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("FindProtocol(): Unable to find correct protocol!\n");
return 1;
}
else
printf("FindProtocol(): Correct protocol found!\n");
if (dwNumProtocols == 0)
{
printf("FindProtocol(): No NetBIOS capable providers found!\n");
return 1;
}
else
printf("FindProtocol(): NetBIOS capable providers found!\n");
}
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;
}
else
printf("GlobalAlloc() looks fine!\n");
// 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 with error code %d\n", WSAGetLastError());
return 1;
}
else
printf("WSACreateEvent() is OK!\n");
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 with error code %d\n", WSAGetLastError());
return 1;
}
else
printf("socket() is OK!\n");
if (WSAConnect(socks[i], (SOCKADDR *)&nbaddr, sizeof(nbaddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR)
{
printf("WSAConnect() failed with error code %d\n", WSAGetLastError());
continue;
}
if (WSAEventSelect(socks[i], hEvents[i], FD_CONNECT) == SOCKET_ERROR)
{
printf("WSAEventSelect() failed with error code %d\n", WSAGetLastError());
return 1;
}
else
printf("WSAEventSelect() is OK!\n");
}
// Wait for one of the connects to succeed
dwIndex = WSAWaitForMultipleEvents(dwNumProtocols, hEvents, FALSE,WSA_INFINITE, FALSE);
if (dwIndex == WSA_WAIT_FAILED)
{
printf("WSAWaitForMultipleEvents() failed with error code %d\n", WSAGetLastError());
return 1;
}
else
printf("WSAWaitForMultipleEvents() is OK!\n");
// 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 with error code %d\n", WSAGetLastError());
}
else
printf("ioctlsocket(FIONBIO) is OK!\n");
memset(szMessage, '$', dwSize);
for (i=0; i < dwCount ;i++)
{
// Send the message to the server
dwRet = send(socks[dwIndex], szMessage, dwSize, 0);
if (dwRet == 0)
{
printf("send() failed coz of graceful close...\n");
closesocket(socks[dwIndex]);
return 0;
}
else if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
{
i--;
continue;
}
else
{
printf("send() failed with error code %d\n", dwErr);
return 1;
}
}
else
printf("send() looks fine!\n");
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("recv() failed coz of graceful close!\n");
closesocket(socks[dwIndex]);
return 0;
}
else if (dwRet == SOCKET_ERROR)
{
if ((dwErr = WSAGetLastError()) == WSAEWOULDBLOCK)
{
i--;
continue;
}
else
{
printf("recv() failed with error code %d\n", dwErr);
return 1;
}
}
else
printf("recv() is OK!\n");
printf("Received money: ");
for(j=0;szMessage[j] == '$';j++)
printf("%c", szMessage[j]);
printf("\nRead %d bytes...\n", dwRet);
}
printf("Cleaning up and de-allocation...\n");
closesocket(socks[dwIndex]);
for (i=0; i < dwNumProtocols ;i++)
WSACloseEvent(hEvents[i]);
GlobalFree(wsapi);
GlobalFree(socks);
GlobalFree(hEvents);
WSACleanup();
return 0;
}
Add the wsnbdef.h include and its definition, wsnbdef.cpp files previously created for the server program into this project. Firstly we copy both files and paste them into the project folder.
---------------------------------------------------------
Then add those files to the client project.
Build and run the project. The following screenshot shows a sample output.
Firstly we run the server program. The following screenshot shows the sample output showing the server is listening for connection.
Then we run the client program. The following screenshot shows a sample output.
Then, the following screenshot shows the server output when the communication was completed.
WARNING! The previous program example not so 'stable'. However we just want to see the working sample of using various APIs for Netbios. Finally, for this section you may want to read the Tips for Writing Windows Sockets Apps That Use AF_NETBIOS.
< NetBIOS Server Examples | Winsock2 Supported Protocols Main | AppleTalk Protocol >