What do we have in this chapter?
Winsock Tutorial
Winsock: Story 1Winsock: Story 2Winsock: Story 3Winsock: Example 1Winsock: Example 2Winsock: Example 3Winsock: Example 4Winsock: Example 5Winsock: Example 6Winsock: Example 7Winsock: Example 8Winsock: Example 9Winsock: Example 10Winsock: Example 11Winsock: Example 12Winsock: Reference 1Winsock: Reference 2Winsock: Reference 3Winsock: Reference 4Another Complete and Advanced C & Winsock2 Programming Tutorial |
My Training Period: hours
Machine’s OS is standalone Windows XP Pro with SP2 except whenever mentioned. Compiler used was Visual C++ 2003 .Net 1.1. Beware the codes that span more than one line. Program examples have been tested for Non Destructive Test. All information compiled for Windows 2000 (NT5.0) above and...
Abilities:
addrinfo Structure
freeaddrinfo()
|
||||||||||||||||||||||||||||||||||||
|
|
|||||||||||||||||||||||||||||||||||||
send() Program Example
For the program example that demonstrates the use of the send() functions on server and client please refer to the previous chapter.
A Complete client-server program example
The following codes are server and client program examples that used the previous discussed Winsock functions and structures. In this case, to make the client-server communication possible you have to make the server settings (through the arguments- protocol, port number etc.) must match with the client settings. For example if you choose to run the UDP server, the client also must be UDP client. Please run the server program first and you can run the client from different computers. In this example the server and client have been run using the default values of arguments on local Windows Xp Pro machine.
/* Server program example for IPv4 */
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DEFAULT_PORT 2007
// default TCP socket type
#define DEFAULT_PROTO SOCK_STREAM
void Usage(char *progname)
{
fprintf(stderr,"Usage: %s -p [protocol] -e [port_num] -i [ip_address]\n", progname);
fprintf(stderr,"Where:\n\t- protocol is one of TCP or UDP\n");
fprintf(stderr,"\t- port_num is the port to listen on\n");
fprintf(stderr,"\t- ip_address is the ip address (in dotted\n");
fprintf(stderr,"\t decimal notation) to bind to. But it is not useful here...\n");
fprintf(stderr,"\t- Hit Ctrl-C to terminate server program...\n");
fprintf(stderr,"\t- The defaults are TCP, 2007 and INADDR_ANY.\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv)
{
char Buffer[128];
char *ip_address= NULL;
unsigned short port=DEFAULT_PORT;
int retval;
int fromlen;
int i;
int socket_type = DEFAULT_PROTO;
struct sockaddr_in local, from;
WSADATA wsaData;
SOCKET listen_socket, msgsock;
/* Parse arguments, if there are arguments supplied */
if (argc > 1)
{
for(i=1; i<argc; i++)
{
// switches or options...
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{
// Change to lower...if any
switch(tolower(argv[i][1]))
{
// if -p or /p
case 'p':
if (!stricmp(argv[i+1], "TCP"))
socket_type = SOCK_STREAM;
else if (!stricmp(argv[i+1], "UDP"))
socket_type = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;
// if -i or /i, for server it is not so useful...
case 'i':
ip_address = argv[++i];
break;
// if -e or /e
case 'e':
port = atoi(argv[++i]);
break;
// No match...
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
// Request Winsock version 2.2
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
fprintf(stderr,"Server: WSAStartup() failed with error %d\n", retval);
WSACleanup();
return -1;
}
else
printf("Server: WSAStartup() is OK.\n");
if (port == 0)
{
Usage(argv[0]);
}
local.sin_family = AF_INET;
local.sin_addr.s_addr = (!ip_address) ? INADDR_ANY:inet_addr(ip_address);
/* Port MUST be in Network Byte Order */
local.sin_port = htons(port);
// TCP socket
listen_socket = socket(AF_INET, socket_type,0);
if (listen_socket == INVALID_SOCKET){
fprintf(stderr,"Server: socket() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Server: socket() is OK.\n");
// bind() associates a local address and port combination with the socket just created.
// This is most useful when the application is a
// server that has a well-known port that clients know about in advance.
if (bind(listen_socket, (struct sockaddr*)&local, sizeof(local)) == SOCKET_ERROR)
{
fprintf(stderr,"Server: bind() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Server: bind() is OK.\n");
// So far, everything we did was applicable to TCP as well as UDP.
// However, there are certain steps that do not work when the server is
// using UDP. We cannot listen() on a UDP socket.
if (socket_type != SOCK_DGRAM)
{
if (listen(listen_socket,5) == SOCKET_ERROR)
{
fprintf(stderr,"Server: listen() failed with error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Server: listen() is OK.\n");
}
printf("Server: %s: I'm listening and waiting connection\non port %d, protocol %s\n", argv[0], port, (socket_type == SOCK_STREAM)?"TCP":"UDP");
while(1)
{
fromlen =sizeof(from);
// accept() doesn't make sense on UDP, since we do not listen()
if (socket_type != SOCK_DGRAM)
{
msgsock = accept(listen_socket, (struct sockaddr*)&from, &fromlen);
if (msgsock == INVALID_SOCKET)
{
fprintf(stderr,"Server: accept() error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Server: accept() is OK.\n");
printf("Server: accepted connection from %s, port %d\n", inet_ntoa(from.sin_addr), htons(from.sin_port)) ;
}
else
msgsock = listen_socket;
// In the case of SOCK_STREAM, the server can do recv() and send() on
// the accepted socket and then close it.
// However, for SOCK_DGRAM (UDP), the server will do recvfrom() and sendto() in a loop.
if (socket_type != SOCK_DGRAM)
retval = recv(msgsock, Buffer, sizeof(Buffer), 0);
else
{
retval = recvfrom(msgsock,Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, &fromlen);
printf("Server: Received datagram from %s\n", inet_ntoa(from.sin_addr));
}
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Server: recv() failed: error %d\n", WSAGetLastError());
closesocket(msgsock);
continue;
}
else
printf("Server: recv() is OK.\n");
if (retval == 0)
{
printf("Server: Client closed connection.\n");
closesocket(msgsock);
continue;
}
printf("Server: Received %d bytes, data \"%s\" from client\n", retval, Buffer);
printf("Server: Echoing the same data back to client...\n");
if (socket_type != SOCK_DGRAM)
retval = send(msgsock, Buffer, sizeof(Buffer), 0);
else
retval = sendto(msgsock, Buffer, sizeof(Buffer), 0, (struct sockaddr *)&from, fromlen);
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Server: send() failed: error %d\n", WSAGetLastError());
}
else
printf("Server: send() is OK.\n");
if (socket_type != SOCK_DGRAM)
{
printf("Server: I'm waiting more connection, try running the client\n");
printf("Server: program from the same computer or other computer...\n");
closesocket(msgsock);
}
else
printf("Server: UDP server looping back for more requests\n");
continue;
}
return 0;
}
Sample output:
|
Figure 1 |
The following is the client program.
// Client program example
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define DEFAULT_PORT 2007
// TCP socket type
#define DEFAULT_PROTO SOCK_STREAM
void Usage(char *progname)
{
fprintf(stderr,"Usage: %s -p [protocol] -n [server name/IP] -e [port_num] -l [iterations]\n", progname);
fprintf(stderr,"Where:\n\tprotocol is one of TCP or UDP\n");
fprintf(stderr,"\t- server is the IP address or name of server\n");
fprintf(stderr,"\t- port_num is the port to listen on\n");
fprintf(stderr,"\t- iterations is the number of loops to execute.\n");
fprintf(stderr,"\t- (-l by itself makes client run in an infinite loop,\n");
fprintf(stderr,"\t- Hit Ctrl-C to terminate it)\n");
fprintf(stderr,"\t- The defaults are TCP , localhost and 2007\n");
WSACleanup();
exit(1);
}
int main(int argc, char **argv)
{
char Buffer[128];
// default to localhost
char *server_name= "localhost";
unsigned short port = DEFAULT_PORT;
int retval, loopflag = 0;
int i, loopcount, maxloop=-1;
unsigned int addr;
int socket_type = DEFAULT_PROTO;
struct sockaddr_in server;
struct hostent *hp;
WSADATA wsaData;
SOCKET conn_socket;
if (argc >1)
{
for(i=1; i<argc; i++)
{
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{
switch(tolower(argv[i][1]))
{
case 'p':
if (!stricmp(argv[i+1], "TCP"))
socket_type = SOCK_STREAM;
else if (!stricmp(argv[i+1], "UDP"))
socket_type = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;
case 'n':
server_name = argv[++i];
break;
case 'e':
port = atoi(argv[++i]);
break;
case 'l':
loopflag =1;
if (argv[i+1]) {
if (argv[i+1][0] != '-')
maxloop = atoi(argv[i+1]);
}
else
maxloop = -1;
i++;
break;
default:
Usage(argv[0]);
break;
}
}
else
Usage(argv[0]);
}
}
if ((retval = WSAStartup(0x202, &wsaData)) != 0)
{
fprintf(stderr,"Client: WSAStartup() failed with error %d\n", retval);
WSACleanup();
return -1;
}
else
printf("Client: WSAStartup() is OK.\n");
if (port == 0)
{
Usage(argv[0]);
}
// Attempt to detect if we should call gethostbyname() or gethostbyaddr()
if (isalpha(server_name[0]))
{ // server address is a name
hp = gethostbyname(server_name);
}
else
{ // Convert nnn.nnn address to a usable one
addr = inet_addr(server_name);
hp = gethostbyaddr((char *)&addr, 4, AF_INET);
}
if (hp == NULL )
{
fprintf(stderr,"Client: Cannot resolve address \"%s\": Error %d\n", server_name, WSAGetLastError());
WSACleanup();
exit(1);
}
else
printf("Client: gethostbyaddr() is OK.\n");
// Copy the resolved information into the sockaddr_in structure
memset(&server, 0, sizeof(server));
memcpy(&(server.sin_addr), hp->h_addr, hp->h_length);
server.sin_family = hp->h_addrtype;
server.sin_port = htons(port);
conn_socket = socket(AF_INET, socket_type, 0); /* Open a socket */
if (conn_socket <0 )
{
fprintf(stderr,"Client: Error Opening socket: Error %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Client: socket() is OK.\n");
// 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()
printf("Client: Client connecting to: %s.\n", hp->h_name);
if (connect(conn_socket, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
fprintf(stderr,"Client: connect() failed: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Client: connect() is OK.\n");
// Test sending some string
loopcount = 0;
while(1)
{
wsprintf(Buffer,"This is a test message from client #%d", loopcount++);
retval = send(conn_socket, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Client: send() failed: error %d.\n", WSAGetLastError());
WSACleanup();
return -1;
}
else
printf("Client: send() is OK.\n");
printf("Client: Sent data \"%s\"\n", Buffer);
retval = recv(conn_socket, Buffer, sizeof(Buffer), 0);
if (retval == SOCKET_ERROR)
{
fprintf(stderr,"Client: recv() failed: error %d.\n", WSAGetLastError());
closesocket(conn_socket);
WSACleanup();
return -1;
}
else
printf("Client: recv() is OK.\n");
// We are not likely to see this with UDP, since there is no
// 'connection' established.
if (retval == 0)
{
printf("Client: Server closed connection.\n");
closesocket(conn_socket);
WSACleanup();
return -1;
}
printf("Client: Received %d bytes, data \"%s\" from server.\n", retval, Buffer);
if (!loopflag)
{
printf("Client: Terminating connection...\n");
break;
}
else
{
if ((loopcount >= maxloop) && (maxloop >0))
break;
}
}
closesocket(conn_socket);
WSACleanup();
return 0;
}
The following is an output when the client program has been run twice using the default arguments. Remember that you have to run the server program first.
C:\>myclient -
Usage: myclient -p [protocol] -n [server name/IP] -e [port_num] -l [iterations]
Where:
protocol is one of TCP or UDP
- server is the IP address or name of server
- port_num is the port to listen on
- iterations is the number of loops to execute.
- (-l by itself makes client run in an infinite loop,
- Hit Ctrl-C to terminate it)
- The defaults are TCP , localhost and 2007
C:\>myclient -p TCP -n 127.0.0.1 -e 5656 -l 3
Client: WSAStartup() is OK.
Client: gethostbyaddr() is OK.
Client: socket() is OK.
Client: Client connecting to: localhost.
Client: connect() is OK.
Client: send() is OK.
Client: Sent data "This is a test message from client #0"
Client: recv() is OK.
Client: Received 128 bytes, data "This is a test message from client #0" from server.
Client: send() is OK.
Client: Sent data "This is a test message from client #1"
Client: recv() failed: error 10053.
C:\>myclient -p TCP -n 127.0.0.1 -e 5656 -l 3
Client: WSAStartup() is OK.
Client: gethostbyaddr() is OK.
Client: socket() is OK.
Client: Client connecting to: localhost.
Client: connect() is OK.
Client: send() is OK.
Client: Sent data "This is a test message from client #0"
Client: recv() is OK.
Client: Received 128 bytes, data "This is a test message from client #0" from server.
Client: send() is OK.
Client: Sent data "This is a test message from client #1"
Client: recv() failed: error 10053.
C:\>
Notice that the iterations is not working. And the server console output is shown below after the same client program has been run twice.
C:\>mywinsock -
Usage: mywinsock -p [protocol] -e [port_num] -i [ip_address]
Where:
- protocol is one of TCP or UDP
- port_num is the port to listen on
- ip_address is the ip address (in dotted
decimal notation) to bind to. But it is not useful here...
- Hit Ctrl-C to terminate server program...
- The defaults are TCP, 2007 and INADDR_ANY.
C:\>mywinsock -p TCP -e 5656
Server: WSAStartup() is OK.
Server: socket() is OK.
Server: bind() is OK.
Server: listen() is OK.
Server: mywinsock: I'm listening and waiting connection
on port 5656, protocol TCP
Server: accept() is OK.
Server: accepted connection from 127.0.0.1, port 1031
Server: recv() is OK.
Server: Received 128 bytes, data "This is a test message from client #0" from client
Server: Echoing the same data back to client...
Server: send() is OK.
Server: I'm waiting more connection, try running the client
Server: program from the same computer or other computer...
Server: accept() is OK.
Server: accepted connection from 127.0.0.1, port 1032
Server: recv() is OK.
Server: Received 128 bytes, data "This is a test message from client #0" from client
Server: Echoing the same data back to client...
Server: send() is OK.
Server: I'm waiting more connection, try running the client
Server: program from the same computer or other computer...
_
The following console outputs are the previous client-server program examples re-compiled using Visual C++ 6.0 and using public IPs.

Figure 2

Figure 3

Figure 4
Further reading and digging:
Linux Sockets: Story and program examples.
Structure, enum, union and typedef story can be found struct, enum, union & typedef tutorial.
A complete info on Windows socket reference from MSDN which include managed and unmanaged API doc.
For Multibytes, Unicode characters and Localization please refer to Multibyte, Unicode and wide characters (Story) and Win32 Windows & Users tutorial (Implementation).
Windows data type information is Win32 - Windows data types.
Check the best selling C / C++ and Windows books at Amazon.com.