Tenouk C & C++ | Winsock Prog. Example 9 | Main | Winsock Prog. Example 11 >| Site Index | Download | Linux Socket | Winsock in .NET


 

 

 

 

 

 

WINSOCK 2

WINDOWS SOCKET: PROGRAM EXAMPLES PART 10

 

 

 

 

 

 

 

 

What do we have in this chapter?

  1. addrinfo Structure

  2. freeaddrinfo()

  3. send() Program Example

  4. A Complete client-server program example

 

 

Winsock Tutorial

 

Winsock: Story 1

Winsock: Story 2

Winsock: Story 3

Winsock: Example 1

Winsock: Example 2

Winsock: Example 3

Winsock: Example 4

Winsock: Example 5

Winsock: Example 6

Winsock: Example 7

Winsock: Example 8

Winsock: Example 9

Winsock: Example 10

Winsock: Example 11

Winsock: Example 12

Winsock: Reference 1

Winsock: Reference 2

Winsock: Reference 3

Winsock: Reference 4

Another 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...

 

  1. Related functions, structures and macros used in the program examples have been dumped at Winsock structure & function 1 and Winsock structure & function 2.

  2. Other related and required information (if any) not available in no. 2 can be found at MSDN & Visual C++ online reference.

 

Abilities:

  • Able to understand the advanced networking of the TCP/IP.

  • Able to understand Winsock implementation and operations 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.

addrinfo Structure

 

Item

Description

Structure

addrinfo

Info

Used by the getaddrinfo() function to hold host address information.

Definition

typedef struct addrinfo {

  int ai_flags;

  int ai_family;

  int ai_socktype;

  int ai_protocol;

  size_t ai_addrlen;

  char* ai_canonname;

  struct sockaddr* ai_addr;

  struct addrinfo* ai_next;

} addrinfo;

Members

ai_flags - Flags that indicate options used in the getaddrinfo() function. See AI_PASSIVE, AI_CANONNAME, and AI_NUMERICHOST.

ai_family - Protocol family, such as PF_INET.

ai_socktype - Socket type, such as SOCK_RAW, SOCK_STREAM, or SOCK_DGRAM.

ai_protocol - Protocol, such as IPPROTO_TCP or IPPROTO_UDP. For protocols other than IPv4 and IPv6, set ai_protocol to zero.

ai_addrlen - Length of the ai_addr member, in bytes.

ai_canonname - Canonical name for the host.

ai_addr - Pointer to a sockaddr structure.

ai_next - Pointer to the next structure in a linked list. This parameter is set to NULL in the last addrinfo structure of a linked list.

Header file

<winsock2.h>, <ws2tcpip.h>.

Remark

Declared in ws2tcpip.h; include wspiapi.h for Windows 95/98/Me, Windows 2000 and Windows NT.

 

Table 1

 

freeaddrinfo()

 

Item

Description

Function

freeaddrinfo()

Use

Frees address information that the getaddrinfo() function dynamically allocates in its addrinfo structures.

Prototype

void freeaddrinfo(struct addrinfo* ai);

Parameters

ai - [in] Pointer to the addrinfo structure or linked list of addrinfo structures to be freed. All dynamic storage pointed to within the addrinfo structure(s) is also freed.

Return value

This function has no return values.

Include file

<winsock2.h>, <ws2tcpip.h>

Library

ws2_32.lib

Remark

Declared in ws2tcpip.h; include wspiapi.h for Windows 95/98/Me, Windows 2000 and Windows NT. The freeaddrinfo() function frees the initial addrinfo structure pointed to in its ai parameter, including any buffers to which its members point, then continues freeing any addrinfo structures linked by its ai_next member. The freeaddrinfo() function continues freeing linked structures until a NULL ai_next member is encountered. Macros in the Winsock header file define the mixed-case function name FreeAddrInfo() to freeaddrinfo(); either spelling is acceptable.

 

Table 2

 

 

 

 

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:

 

  1. Linux Sockets: Story and program examples.

  2. Linux and TCP/IP.

  3. Structure, enum, union and typedef story can be found struct, enum, union & typedef tutorial.

  4. A complete info on Windows socket reference from MSDN which include managed and unmanaged API doc.

  5. For Multibytes, Unicode characters and Localization please refer to Multibyte, Unicode and wide characters (Story) and Win32 Windows & Users tutorial (Implementation).

  6. Windows data type information is Win32 - Windows data types.

  7. Check the best selling C / C++ and Windows books at Amazon.com.

 

 

 

 

 

 


 

Tenouk C & C++ | Winsock Prog. Example 9 | Main | Winsock Prog. Example 11 >| Site Index | Download | Linux Socket | Winsock in .NET