CAVEAT: This document assumes that you are familiar with ANSI C
programming. It is intended as a brief introduction to the concept of TCP/IP socket access
to ADR cards. The sample code is provided for demonstration purposes only. Although the
programs compile and run they are not a complete implementation.
This page describes the C code in the client program.
First we include the header files for all the API's and structures that we use.
#include <Winsock.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <memory.h>
#include <time.h>
The PrintHelp function provides some terse assistance for the user.
void PrintHelp(); // declaration of our help function
Now we declare our main procedure, our local variables and perform some prepartory
steps similar to the server program. See the previous discussion about the server for
details.
//
// ADR Sock Client main entry point
//
void main(int argc, char*argv[])
{
BOOL bStillOK;
int socket_id; // id from socket function
int rcSockopt; // return code from setsockopt
int rcConnect; // return code from connect function
int rcSend; // return code from write to socket
int rcRecv; // return code from receive
int turn_on_option_flag;
int iRC;
struct sockaddr_in sock_struc;
struct hostent *hostptr;
struct servent *servptr;
time_t starttime;
struct tm *today;
WORD wVersionRequested;
WSADATA wsaData;
char node_name[32];
char message[80];
char datebuf[128];
char timebuf[128];
char conbuf[256];
bStillOK = TRUE; // assume things are OK
// first check args
if (argc < 4 || argc > 4
|| !strcmp(argv[1],"-h") || !strcmp(argv[1],"-H")
|| !strcmp(argv[1],"-?") || !strcmp(argv[1],"/h")
|| !strcmp(argv[1],"/H") || !strcmp(argv[1],"/?")
|| !strcmp(argv[1],"help") || !strcmp(argv[1],"HELP"))
{
PrintHelp();
bStillOK = FALSE;
} // end if
if (bStillOK)
{
time(&starttime);
today = localtime (&starttime);
strftime( datebuf, 128,
"Today is %A, day %d of %B in the year %Y.\n",
today );
printf(datebuf);
_strtime( timebuf );
printf( "OS time:\t\t\t\t%s\n", timebuf );
wVersionRequested = MAKEWORD (1,1);
if((iRC = WSAStartup(wVersionRequested, &wsaData)) != 0)
{
printf ("startup failed, rc= %d\n", iRC);
bStillOK = FALSE;
} // end if
} // endif
The gethostbyname call looks up the IP address for a computer name. Here the server
computer name is the first parameter of the ADRSockClient program. The IP address
retrieved is the one that you associated with the server computer name in the Hosts file.
Sidebar: the gethostbyname call can also access Domain Name Services (DNS) to resolve
an address.
if (bStillOK)
{
strcpy (node_name, argv[1]); // name of server computer
hostptr = gethostbyname (node_name);
if (hostptr == (struct hostent *)NULL)
{
printf ("gethostbyname failed - check HOSTS file\n");
bStillOK = FALSE;
} // end if
} // end if
Next we create a socket and set its options. A real application has to check for errors
returned by the socket and the setsockopt calls. Here, I simply proceed obliviously.
The setsockopt turns on the TCP_NODELAY option of the IPPROTO_TCP protocol. This means
that messages are sent immediately and not combined in an attempt to fill up a packet.
The getservbyname call was described in the server-side discussion.
if (bStillOK)
{
socket_id = socket (AF_INET, SOCK_STREAM,0);
rcSockopt = setsockopt(socket_id, IPPROTO_TCP,
TCP_NODELAY,
(char *) &turn_on_option_flag,
sizeof(turn_on_option_flag));
servptr = getservbyname ("ADRlink", "tcp");
if (servptr == (struct servent *)NULL)
{
printf ("cannot find service - check SERVICES file\n");
bStillOK = FALSE;
} // end if
} // end if
We load the sock_struc with the address information of the server and the port number
for ADRlink. The connect call will try to establish communication with the server. The
server will accept the connection as described in the server-side code. This establishes a
socket connection with a client end-point identified by socket_id and a server endpoint
identified by iSocket (in ADRSockSrv).
if (bStillOK)
{
sock_struc.sin_family = hostptr->h_addrtype;
memcpy((char *)&(sock_struc.sin_addr), hostptr->h_addr,
hostptr->h_length);
sock_struc.sin_port = servptr->s_port;
rcConnect = connect (socket_id,
(struct sockaddr *)&(sock_struc),
sizeof(struct sockaddr));
if (rcConnect == SOCKET_ERROR)
{
printf ("connect failed: rc is %d ", rcConnect);
errno = WSAGetLastError();
printf ("errno is %d\n",errno);
bStillOK = FALSE;
} // end if
} // end if
We build the message by concatenating the "repsonse expected" parameter and
the "command" parameter. A trailing carriage return, "/r" terminates
the message. The trailing carriage return indicates the end of the command to both the
ADRSockSrv program and the ADR card.
The message is sent to the server over the socket connection.
if (bStillOK)
{
strcpy(message,argv[2]);
strcat(message,argv[3]);
strcat(message,"\r");
rcSend = send (socket_id, message, strlen(message), 0);
if (rcSend == SOCKET_ERROR)
{
printf ("send failed: rc is %d ",rcSend);
errno = WSAGetLastError();
printf ("errno is %d\n",errno);
bStillOK = FALSE;
} // end if
} // end if
If we are expecting a reply then we issue a recv call on the socket connection. The
recv call waits until a response is received or the socket connection is closed by the
server.
if (bStillOK && (*argv[2] == 'y'|| *argv[2] == 'Y'))
{
rcRecv = recv (socket_id, conbuf, BUFSIZ, 0);
if (rcRecv == SOCKET_ERROR)
{
printf ("recv failed: rc is %d ",rcRecv);
errno = WSAGetLastError();
printf ("errno is %d\n",errno);
bStillOK = FALSE;
}
else
{
conbuf[rcRecv] = '\0';
printf("value received is: %s",conbuf);
} // end if
} // end if
Finally, release the Windows Socket Architecture resources and exit.
WSACleanup();
} // end main
To retrieve the source code used in this example via email, send your name and
address to tfortin@vianet.on.ca ( for our snail
mail list ) and we will send the example via email.
Please indicate that you want the ADRSocketDemo. |