344 lines
9.8 KiB
C++
344 lines
9.8 KiB
C++
/******************************************************************************\
|
|
* simplec.c - Simple TCP/UDP client using Winsock 1.1
|
|
*
|
|
* This is a part of the Microsoft Source Code Samples.
|
|
* Copyright 1996 - 2000 Microsoft Corporation.
|
|
* All rights reserved.
|
|
* This source code is only intended as a supplement to
|
|
* Microsoft Development Tools and/or WinHelp documentation.
|
|
* See these sources for detailed information regarding the
|
|
* Microsoft samples programs.
|
|
\******************************************************************************/
|
|
#ifdef _IA64_
|
|
#pragma warning(disable:4127)
|
|
#endif
|
|
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <wspiapi.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <strsafe.h>
|
|
|
|
#define DEFAULT_PORT "5001" // Default server port
|
|
#define DEFAULT_PROTO SOCK_STREAM // Default protocol (TCP)
|
|
#define DEFAULT_BUFFER_LEN 4096 // Default send/recv buffer length
|
|
|
|
//
|
|
// Function: Usage
|
|
//
|
|
// Description:
|
|
// Print the parameters and exit.
|
|
//
|
|
void Usage(char *progname)
|
|
{
|
|
fprintf(stderr, "Usage\n%s -p [protocol] -n [server] -e [endpoint] -l [iterations] [-4] [-6]\n"
|
|
"Where:\n"
|
|
"\t-p protocol - is one of TCP or UDP\n"
|
|
"\t-n server - is the string address or name of server\n"
|
|
"\t-e endpoint - is the port to listen on\n"
|
|
"\t-l iterations - is the number of loops to execute\n"
|
|
"\t -l by itself makes client run in an infinite loop,"
|
|
"\t Hit Ctrl-C to terminate it)\n"
|
|
"\t-4 - force IPv4\n"
|
|
"\t-6 - force IPv6\n"
|
|
"\n"
|
|
"Defaults are TCP, localhost and 5001\n",
|
|
progname
|
|
);
|
|
WSACleanup();
|
|
exit(1);
|
|
}
|
|
|
|
|
|
//
|
|
// Function: main
|
|
//
|
|
// Description:
|
|
// Parse the command line and attempt to connect to the given server.
|
|
// The client will attempt to connect to each address returned by the
|
|
// getaddrinfo call until one succeeds afterwhich it will initiate
|
|
// echoing the data. Once the requested number of sends are issued,
|
|
// the connection is closed. For UDP, this is simply connecting the
|
|
// UDP socket to and endpoint and issuing the requested number of
|
|
// datagram sends and receives.
|
|
//
|
|
int __cdecl main(int argc, char **argv)
|
|
{
|
|
WSADATA wsaData;
|
|
SOCKET conn_socket = INVALID_SOCKET;
|
|
struct addrinfo *results = NULL,
|
|
*addrptr = NULL,
|
|
hints;
|
|
char *server_name = "localhost",
|
|
*port = DEFAULT_PORT,
|
|
Buffer[DEFAULT_BUFFER_LEN],
|
|
hoststr[NI_MAXHOST],
|
|
servstr[NI_MAXSERV];
|
|
int address_family = AF_UNSPEC,
|
|
socket_type = DEFAULT_PROTO;
|
|
int retval,
|
|
loopflag = 0,
|
|
loopcount,
|
|
maxloop = -1,
|
|
i;
|
|
|
|
// Parse the command line
|
|
if (argc >1)
|
|
{
|
|
for (i=1; i < argc; i++)
|
|
{
|
|
if ( (strlen(argv[i]) == 2) && ((argv[i][0] == '-') || (argv[i][0] == '/') ) )
|
|
{
|
|
switch (tolower(argv[i][1]))
|
|
{
|
|
case '4': // Force IPv4
|
|
address_family = AF_INET;
|
|
break;
|
|
|
|
case '6': // Force IPv6
|
|
address_family = AF_INET6;
|
|
break;
|
|
|
|
case 'p': // Protocol (UDP or TCP)
|
|
if (!_strnicmp(argv[i+1], "TCP", 3) )
|
|
socket_type = SOCK_STREAM;
|
|
else if (!_strnicmp(argv[i+1], "UDP", 3) )
|
|
socket_type = SOCK_DGRAM;
|
|
else
|
|
Usage(argv[0]);
|
|
i++;
|
|
break;
|
|
|
|
case 'n': // Server name to connect to
|
|
server_name = argv[++i];
|
|
break;
|
|
|
|
case 'e': // Port number to connect to
|
|
port = argv[++i];
|
|
break;
|
|
|
|
case 'l': // Number of iterations
|
|
loopflag = 1;
|
|
if (i+1 >= argc)
|
|
Usage(argv[0]);
|
|
if (argv[i+1][0] != '-')
|
|
maxloop = atoi(argv[i+1]);
|
|
else
|
|
maxloop = -1;
|
|
i++;
|
|
break;
|
|
|
|
default:
|
|
Usage(argv[0]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
Usage(argv[0]);
|
|
}
|
|
}
|
|
|
|
// Load Winsock
|
|
if ((retval = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
|
|
{
|
|
fprintf(stderr,"WSAStartup failed with error %d\n",retval);
|
|
WSACleanup();
|
|
return -1;
|
|
}
|
|
|
|
// Make sure the wildcard port wasn't specified
|
|
if (_strnicmp(port, "0", 1) == 0)
|
|
Usage(argv[0]);
|
|
|
|
//
|
|
// Resolve the server name
|
|
//
|
|
memset(&hints, 0, sizeof(hints));
|
|
hints.ai_family = address_family;
|
|
hints.ai_socktype = socket_type;
|
|
hints.ai_protocol = ((socket_type == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP);
|
|
|
|
retval = getaddrinfo(
|
|
server_name,
|
|
port,
|
|
&hints,
|
|
&results
|
|
);
|
|
if (retval != 0)
|
|
{
|
|
fprintf(stderr, "getaddrinfo failed: %d\n", retval);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Make sure we got at least one address
|
|
if (results == NULL)
|
|
{
|
|
fprintf(stderr, "Server (%s) name could not be resolved!\n", server_name);
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Walk through the list of addresses returned and connect to each one.
|
|
// Take the first successful connection.
|
|
//
|
|
addrptr = results;
|
|
while (addrptr)
|
|
{
|
|
conn_socket = socket(addrptr->ai_family, addrptr->ai_socktype, addrptr->ai_protocol);
|
|
if (conn_socket == INVALID_SOCKET)
|
|
{
|
|
fprintf(stderr, "socket failed: %d\n", WSAGetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Notice that nothing in this code is specific to whether we
|
|
// are using UDP or TCP.
|
|
// We achieve this by using a simple trick.
|
|
// When connect() is called on a datagram socket, it does not
|
|
// actually establish the connection as a stream (TCP) socket
|
|
// would. Instead, TCP/IP establishes the remote half of the
|
|
// ( LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping.
|
|
// This enables us to use send() and recv() on datagram sockets,
|
|
// instead of recvfrom() and sendto()
|
|
|
|
retval = getnameinfo(
|
|
addrptr->ai_addr,
|
|
(socklen_t)addrptr->ai_addrlen,
|
|
hoststr,
|
|
NI_MAXHOST,
|
|
servstr,
|
|
NI_MAXSERV,
|
|
NI_NUMERICHOST | NI_NUMERICSERV
|
|
);
|
|
if (retval != 0)
|
|
{
|
|
fprintf(stderr, "getnameinfo failed: %d\n", retval);
|
|
goto cleanup;
|
|
}
|
|
|
|
printf("Client attempting connection to: %s port: %s\n", hoststr, servstr);
|
|
|
|
retval = connect(conn_socket, addrptr->ai_addr, (int)addrptr->ai_addrlen);
|
|
if (retval == SOCKET_ERROR)
|
|
{
|
|
closesocket(conn_socket);
|
|
conn_socket = INVALID_SOCKET;
|
|
|
|
addrptr = addrptr->ai_next;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
freeaddrinfo(results);
|
|
results = NULL;
|
|
|
|
// Make sure we got a connection established
|
|
if (conn_socket == INVALID_SOCKET)
|
|
{
|
|
printf("Unable to establish connection...\n");
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
printf("Connection established...\n");
|
|
}
|
|
|
|
//
|
|
// cook up a string to send
|
|
//
|
|
loopcount = 0;
|
|
for (;;)
|
|
{
|
|
StringCbPrintf(Buffer, sizeof(Buffer),
|
|
"This is a small test message [number %d]",
|
|
loopcount++
|
|
);
|
|
|
|
// Send the data
|
|
retval = send(conn_socket, Buffer, lstrlen(Buffer)+1, 0);
|
|
if (retval == SOCKET_ERROR)
|
|
{
|
|
fprintf(stderr,"send failed: error %d\n", WSAGetLastError());
|
|
goto cleanup;
|
|
}
|
|
|
|
printf("wrote %d bytes\n", retval);
|
|
|
|
// Receive the data back
|
|
retval = recv(conn_socket, Buffer, DEFAULT_BUFFER_LEN, 0);
|
|
if (retval == SOCKET_ERROR)
|
|
{
|
|
fprintf(stderr, "recv failed: error %d\n", WSAGetLastError());
|
|
goto cleanup;
|
|
}
|
|
//
|
|
// We are not likely to see this with UDP, since there is no
|
|
// 'connection' established.
|
|
//
|
|
if (retval == 0)
|
|
{
|
|
printf("Server closed connection\n");
|
|
|
|
break;
|
|
}
|
|
|
|
printf("read %d bytes, data [%s] from server\n", retval, Buffer);
|
|
|
|
// See if we need to break out of the loop
|
|
if (loopflag)
|
|
{
|
|
if ( (loopcount >= maxloop) && (maxloop > 0) )
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
//
|
|
// clean up the client connection
|
|
//
|
|
|
|
if (conn_socket != INVALID_SOCKET)
|
|
{
|
|
// Indicate no more data to send
|
|
retval = shutdown(conn_socket, SD_SEND);
|
|
if (retval == SOCKET_ERROR)
|
|
{
|
|
fprintf(stderr, "shutdown failed: %d\n", WSAGetLastError());
|
|
}
|
|
|
|
// Close the socket
|
|
retval = closesocket(conn_socket);
|
|
if (retval == SOCKET_ERROR)
|
|
{
|
|
fprintf(stderr, "closesocket failed: %d\n", WSAGetLastError());
|
|
}
|
|
|
|
conn_socket = INVALID_SOCKET;
|
|
}
|
|
|
|
if (results != NULL)
|
|
{
|
|
freeaddrinfo(results);
|
|
results = NULL;
|
|
}
|
|
|
|
WSACleanup();
|
|
|
|
return 0;
|
|
}
|