| Tenouk.com |< Winsock Program Example 11 | Main | Winsock Functions 1 >| Site Index | Download |
WINSOCK 2
WINDOWS SOCKET: PROGRAM EXAMPLES PART 12
|
|
|
|
Winsock Tutorial
|
My Training Period: hours
Note: This is a continuation from previous Module. 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 :o). All information compiled for Windows 2000 (NT5.0) above and...
Abilities
▪ Able to understand Winsock implementation and operations of the IPv6 through the APIs and program examples. ▪ Able to gather, understand and use the Winsock functions, structures and macros in your programs. ▪ Able to build programs that use Microsoft C/Standard C programming language and Winsock APIs.
And the client program for IPv6 example.
// Client for IPv6 enabled program example #define WIN32_LEAN_AND_MEAN #include <winsock2.h> #include <ws2tcpip.h> #ifndef IPPROTO_IPV6 // For IPv6 #include <tpipv6.h> #endif #include <stdlib.h> #include <stdio.h> #include <string.h>
// This code assumes that at the transport level, the system only supports // one stream protocol (TCP) and one datagram protocol (UDP). Therefore, // specifying a socket type of SOCK_STREAM is equivalent to specifying TCP // and specifying a socket type of SOCK_DGRAM is equivalent to specifying UDP. // // Will use the loopback interface #define DEFAULT_SERVER NULL // Accept either IPv4 or IPv6 #define DEFAULT_FAMILY PF_UNSPEC // TCP socket type #define DEFAULT_SOCKTYPE SOCK_STREAM // Arbitrary, test port #define DEFAULT_PORT "2007" // Number of "extra" bytes to send #define DEFAULT_EXTRA 0 #define BUFFER_SIZE 65536
void Usage(char *ProgName) { fprintf(stderr, "\nSimple socket IPv6 client program.\n"); fprintf(stderr, "\n%s [-s server] [-f family] [-t transport] [-p port] [-b bytes] [-n number]\n\n", ProgName); fprintf(stderr, " server\tServer name or IP address. (default: %s)\n", (DEFAULT_SERVER == NULL) ? "loopback address" : DEFAULT_SERVER); fprintf(stderr, " family\tOne of PF_INET, PF_INET6 or PF_UNSPEC. (default: %s)\n", (DEFAULT_FAMILY == PF_UNSPEC) ? "PF_UNSPEC" : ((DEFAULT_FAMILY == PF_INET) ? "PF_INET" : "PF_INET6")); fprintf(stderr, " transport\tEither TCP or UDP. (default: %s)\n", (DEFAULT_SOCKTYPE == SOCK_STREAM) ? "TCP" : "UDP"); fprintf(stderr, " port\t\tPort on which to connect. (default: %s)\n", DEFAULT_PORT); fprintf(stderr, " bytes\t\tBytes of extra data to send. (default: %d)\n", DEFAULT_EXTRA); fprintf(stderr, " number\tNumber of sends to perform. (default: 1)\n"); fprintf(stderr, " (-n by itself makes client run in an infinite loop,"); fprintf(stderr, " Hit Ctrl-C to terminate)\n"); WSACleanup(); exit(1); }
LPSTR DecodeError(int ErrorCode) { static char Message[1024];
// If this program was multi-threaded, we'd want to use // FORMAT_MESSAGE_ALLOCATE_BUFFER instead of a static buffer here. // (And of course, free the buffer when we were done with it)
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)Message, 1024, NULL); return Message; }
int ReceiveAndPrint(SOCKET ConnSocket, char *Buffer, int BufLen) { int AmountRead;
AmountRead = recv(ConnSocket, Buffer, BufLen, 0); if (AmountRead == SOCKET_ERROR) { fprintf(stderr, "Client: recv() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError())); closesocket(ConnSocket); WSACleanup(); exit(1); } else printf("Client: recv() is OK.\n");
// We are not likely to see this with UDP, since there is no // 'connection' established. if (AmountRead == 0) { printf("Client: Server closed the connection...\n"); closesocket(ConnSocket); WSACleanup(); exit(0); }
printf("Client: Received %d bytes from server: \"%.*s\"\n", AmountRead, AmountRead, Buffer); return AmountRead; }
int main(int argc, char **argv) { char Buffer[BUFFER_SIZE], AddrName[NI_MAXHOST]; char *Server = DEFAULT_SERVER; int Family = DEFAULT_FAMILY; int SocketType = DEFAULT_SOCKTYPE; char *Port = DEFAULT_PORT; int i, RetVal, AddrLen, AmountToSend; int ExtraBytes = DEFAULT_EXTRA; unsigned int Iteration, MaxIterations = 1; BOOL RunForever = FALSE; WSADATA wsaData; ADDRINFO Hints, *AddrInfo, *AI; SOCKET ConnSocket; struct sockaddr_storage Addr;
printf("Usage: %s [-s server] [-f family] [-t transport] [-p port] [-b bytes] [-n number]\n", argv[0]); printf("Example: %s -s 127.0.0.1 -f PF_INET6 -t TCP -p 1234 -b 1024 -n 4\n", argv[0]); printf("Else, default values used.\n\n");
if (argc > 1) { for (i = 1;i < argc; i++) { if (((argv[i][0] == '-') || (argv[i][0] == '/')) && (argv[i][1] != 0) && (argv[i][2] == 0)) { switch(tolower(argv[i][1])) { case 'f': if (!argv[i+1]) Usage(argv[0]); if (!stricmp(argv[i+1], "PF_INET")) Family = PF_INET; else if (!stricmp(argv[i+1], "PF_INET6")) Family = PF_INET6; else if (!stricmp(argv[i+1], "PF_UNSPEC")) Family = PF_UNSPEC; else Usage(argv[0]); i++; break;
case 't': if (!argv[i+1]) Usage(argv[0]); if (!stricmp(argv[i+1], "TCP")) SocketType = SOCK_STREAM; else if (!stricmp(argv[i+1], "UDP")) SocketType = SOCK_DGRAM; else Usage(argv[0]); i++; break;
case 's': if (argv[i+1]) { if (argv[i+1][0] != '-') { Server = argv[++i]; break; } } Usage(argv[0]); break;
case 'p': if (argv[i+1]) { if (argv[i+1][0] != '-') { Port = argv[++i]; break; } } Usage(argv[0]); break;
case 'b': if (argv[i+1]) { if (argv[i+1][0] != '-') { ExtraBytes = atoi(argv[++i]); if (ExtraBytes > sizeof(Buffer) - sizeof("Message #4294967295")) Usage(argv[0]); break; } } Usage(argv[0]); break;
case 'n': if (argv[i+1]) { if (argv[i+1][0] != '-') { MaxIterations = atoi(argv[++i]); break; } } RunForever = TRUE; break;
default: Usage(argv[0]); break; } } else Usage(argv[0]); } }
// Request for Winsock version 2.2. if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) { fprintf(stderr, "Client: WSAStartup() failed with error %d: %s\n", RetVal, DecodeError(RetVal)); WSACleanup(); return -1; } else printf("Client: WSAStartup() is OK.\n");
// By not setting the AI_PASSIVE flag in the hints to getaddrinfo, we're // indicating that we intend to use the resulting address(es) to connect // to a service. This means that when the Server parameter is NULL, // getaddrinfo will return one entry per allowed protocol family // containing the loopback address for that family. memset(&Hints, 0, sizeof(Hints)); Hints.ai_family = Family; Hints.ai_socktype = SocketType; RetVal = getaddrinfo(Server, Port, &Hints, &AddrInfo); if (RetVal != 0) { fprintf(stderr, "Client: Cannot resolve address [%s] and port [%s], error %d: %s\n", Server, Port, RetVal, gai_strerror(RetVal)); WSACleanup(); return -1; } else printf("Client: getaddrinfo() is OK, name resolved.\n");
// Try each address getaddrinfo returned, until we find one to which // we can successfully connect. for (AI = AddrInfo; AI != NULL; AI = AI->ai_next) { // Open a socket with the correct address family for this address. ConnSocket = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol); if (ConnSocket == INVALID_SOCKET) { fprintf(stderr,"Client: Error Opening socket, error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError())); continue; } else printf("Client: socket() is OK.\n");
// Notice that nothing in this code is specific to whether we // are using UDP or TCP. // // 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: Attempting to connect to: %s\n", Server ? Server : "localhost"); if (connect(ConnSocket, AI->ai_addr, int(AI->ai_addrlen)) != SOCKET_ERROR) break; else printf("Client: connect() is OK.\n");
i = WSAGetLastError(); if (getnameinfo(AI->ai_addr, int(AI->ai_addrlen), AddrName, sizeof(AddrName), NULL, 0, NI_NUMERICHOST) != 0) strcpy(AddrName, "<unknown>"); fprintf(stderr, "Client: connect() to %s failed with error %d: %s\n", AddrName, i, DecodeError(i)); closesocket(ConnSocket); }
if (AI == NULL) { fprintf(stderr, "Client: Fatal error: unable to connect to the server.\n"); WSACleanup(); return -1; }
// This demonstrates how to determine to where a socket is connected. AddrLen = sizeof(Addr); if (getpeername(ConnSocket, (LPSOCKADDR)&Addr, &AddrLen) == SOCKET_ERROR) { fprintf(stderr, "Client: getpeername() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError())); } else { if (getnameinfo((LPSOCKADDR)&Addr, AddrLen, AddrName, sizeof(AddrName), NULL, 0, NI_NUMERICHOST) != 0) strcpy(AddrName, "<unknown>"); printf("Client: Connected to %s, port %d, protocol %s, protocol family %s\n", AddrName, ntohs(SS_PORT(&Addr)), (AI->ai_socktype == SOCK_STREAM) ? "TCP" : "UDP", (AI->ai_family == PF_INET) ? "PF_INET" : "PF_INET6"); }
// We are done with the address info chain, so we can free it. freeaddrinfo(AddrInfo);
// Find out what local address and port the system picked for us. AddrLen = sizeof(Addr); if (getsockname(ConnSocket, (LPSOCKADDR)&Addr, &AddrLen) == SOCKET_ERROR) { fprintf(stderr, "Client: getsockname() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError())); } else { printf("Client: getsockname() is OK.\n"); if (getnameinfo((LPSOCKADDR)&Addr, AddrLen, AddrName, sizeof(AddrName), NULL, 0, NI_NUMERICHOST) != 0) strcpy(AddrName, "<unknown>"); printf("Client: Using local address %s, port %d\n", AddrName, ntohs(SS_PORT(&Addr))); }
// Send and receive in a loop for the requested number of iterations. for (Iteration = 0; RunForever || Iteration < MaxIterations; Iteration++) { // compose a message to send. AmountToSend = sprintf(Buffer, "This is message #%u", Iteration + 1); for (i = 0; i < ExtraBytes; i++) { Buffer[AmountToSend++] = (char)((i & 0x3f) + 0x20); }
// Send the message. Since we are using a blocking socket, this // call shouldn't return until it's able to send the entire amount. RetVal = send(ConnSocket, Buffer, AmountToSend, 0); if (RetVal == SOCKET_ERROR) { fprintf(stderr, "Client: send() failed with error %d: %s\n", WSAGetLastError(), DecodeError(WSAGetLastError())); WSACleanup(); return -1; } else printf("Client: send() is OK.\n");
printf("Client: Sent %d bytes (out of %d bytes) of data: \"%.*s\"\n", RetVal, AmountToSend, AmountToSend, Buffer);
// Clear buffer just to prove we're really receiving something. memset(Buffer, 0, sizeof(Buffer));
// Receive and print server's reply. ReceiveAndPrint(ConnSocket, Buffer, sizeof(Buffer)); }
// Tell system we're done sending. printf("Client: Sending done...\n"); shutdown(ConnSocket, SD_SEND);
// Since TCP does not preserve message boundaries, there may still // be more data arriving from the server. So we continue to receive // data until the server closes the connection. if (SocketType == SOCK_STREAM) while (ReceiveAndPrint(ConnSocket, Buffer, sizeof(Buffer)) != 0) ;
closesocket(ConnSocket); WSACleanup(); return 0; }
The client program’s output.
C:\>myclient -s 127.0.0.1 -f PF_INET -t TCP -p 12345 -b 32 -n 4 Usage: myclient [-s server] [-f family] [-t transport] [-p port] [-b bytes] [-n number] Example: myclient -s 127.0.0.1 -f PF_INET6 -t TCP -p 1234 -b 1024 -n 4 Else, default values used.
Client: WSAStartup() is OK. Client: getaddrinfo() is OK, name resolved.
|