Digi Homepage Making Device Networking Easy.
 

WSA TCP Server Sample

Introduction

This sample demonstrates how to write a TCP server application using the Windows Socket Architecture (WSA) to communicate with a device server.

For the purpose of this demonstration, the server application creates a networking socket it uses to listen for incoming networking connections. A TCP connection is initiated by the device server to the sample application through the use of its AutoConnect feature and a serial loopback plug. Once the connection is established, the sample application attempts to transmit and receive data from the device server.

Device Server Setup

This sample was designed to operate with the first port on the device server, and requires that the port be configured to automatically initiate an TCP connection when carrier is detected (DCD goes high).

Configure the device server
  1. Access the module’s web interface by entering its IP address in a browser’s URL window.
  2. Choose Serial Ports from the Configuration menu.
  3. Configure the module to function as a TCP client by doing the following:
    1. Click the TCP tab.
    2. Check Automatically establish TCP connections.
    3. Specify DCD in the Connect field.
    4. Enter the IP address of the PC running the sample in the Connect To field.
    5. Specify Raw as the Service Type.
    6. Specify 7777 as the TCP port number.
    7. Click Save.

How To Build

This sample has been written and tested with Microsoft Visual C++® 6.0. It contains a Developer Studio project file (.dsp), that can be opened in the development environment for editing and compiling.

To build this sample from within Microsoft Visual C++® 6.0
  1. Select File > Open Workspace... from the main menu.
  2. Change Files of type: to Projects (.dsp).
  3. Locate and open the .dsp file for this sample.
  4. Select Build > Rebuild All menu items to compile the sample.

Step-by-Step

1.  Initialize Windows Sockets

The following initialization code is found early in the program's main function.

WSABUF WSABuf = {0};
WSAStartup(WINSOCK_VERSION, &WSAData);

Initializing Windows Sockets is critical. Failing to initialize Windows Sockets will cause all other socket function calls to fail.

This sample utilizes Windows Sockets version 2.2. Therefore, the macro WINSOCK_VERSION is defined in the system header file WinSock2.h. An application that calls WSAStartup must call WSACleanup when it is done using the Windows Socket services (see step 11).

2.  Create a local socket

The call to create a socket looks like this:

SOCKET Socket = WSASocket(AF_INET, Type, Protocol,
                          NULL, 0, 0);

Where Type is SOCK_STREAM and Protocol is IPPROTO_TCP for a blocking, connection oriented TCP/IP socket.

3.  Bind to a local port

To bind the socket to a local port, call the following function:

bind(Socket, &SockAddr, sizeof(SockAddr));

Binding to a local port must be done before using the socket to calls like WSAConnect, and is used to associate the currently unnamed socket with a local name.

The SockAddr parameter is the SOCKADDR representation of the local name to bind to. This name consists of an address family (for TCP/IP, always AF_INET), a host address, and a port number.

In this sample, the calls to WSASocket and bind are both done in the function MySocketOpen. Since this sample demonstrates a server application, a well-known port (7777) is supplied to the call to MySocketOpen. The same well-known port is also used by the device server as part of its port AutoConnect TCP/IP address information.

4.  Listen for incoming connections

Start listening for incoming connection requests by calling the listen function.

listen(ListenSocket, 1);

Calling listen puts the socket into a relatively inactive mode where it waits for incoming connection requests from a client. Connection requests are queued until processed in a "backlog". The size of this backlog is specified in the second parameter to the call to listen.

5.  Wait to accept an incoming connection

Call WSAAccept to wait for an incoming connection request.

SOCKET ConnectedSocket = WSAAccept(ListenSocket,
                                   &AcceptSockAddr,
                                   &AcceptSockAddrLength,
                                   NULL, 0);

The sample is using blocking sockets, so the call to WSAAccept will not return until there is at least one connection request pending in the backlog queue. The socket value returned from WSAAccept represents the new connection that was just established. The listening socket remains in the passive listening mode, and the new connected socket should be used to communicate with the client.

6.  Initiate an AutoConnect

Attach the serial loopback plug to port 1 on the device server.

Attaching and detaching the serial loopback plug causes the DCD signal to be raised or lowered (respectively). Since the port was configured to AutoConnect when carrier is detected (DCD high), attaching the loopback plug initiates an AutoConnect from the device server to the sample application.

7.  Transmit data

Transmitting data is done by calling WSASend.

WSASend(Socket, &WSABuf, 1, Length, 0, NULL, NULL);

After accepting the incoming connection, the sample uses the socket to transmit some data.

To simplify transmitting data, and to hide many of the details associated with the parameters necessary to call WSASend, this sample uses its own function named MySocketSend.

MySocketSend(ConnectedSocket, SendData, &SendLength);

The only parameters needed for MySocketSend are: MySocket which is the socket returned from MySocketOpen, SendData which is a pointer to the buffer holding the data to send, and SendLength which is the number of bytes SendData points to.

8.  Receive data

To retrieve data received at the local address, call WSARecv.

WSARecv(Socket, &WSABuf, 1, Length, &Flags,
        NULL, NULL);

With the device server setup with the loopback plug, the data transmitted in the step above will be sent directly back to the sample application.

Like WSASend, WSARecv has a large number of parameters, providing great flexibility at the price of adding to its complexity. Also like WSASend, the sample provides an alternative function, MySocketRecv that is somewhat easier to use.

MySocketRecv(ConnectedSocket, RecvData, &BytesReceived);

The caller to MySocketRecv need only supply the prerequisite MySocket, a buffer RecvData to hold the received data, and BytesReceived which specifies the length of RecvData and on return exactly how many bytes were actually copied into the buffer.

9.  Close the connection

Detach the serial loopback plug to port 1 on the device server.

This causes DCD to be lowered and the device server to properly close the TCP session it has to the sample application.

10.  Close the connected socket

Accomplish this task by calling the following two functions:

shutdown(Socket, SD_BOTH);
closesocket(Socket);

When the sample application is done using the socket, the connection it represents must be terminated properly (shutdown) and any resources it may be using should be released (closesocket).

11.  Cleanup

Before exiting the program, call:

WSACleanup();

For every successful call to WSAStartup an application completes, the application must make one call to WSACleanup.

File List

HexDumpData.cpp
HexDumpData.h
MySocket.cpp
MySocket.h
StdAfx.cpp
StdAfx.h
TCPServer.cpp
TCPServer.dsp

Keywords

WSASocket; bind; listen; WSAAccept; WSASend; WSARecv; shutdown; closesocket; WSACleanup
 
 
Digi International Inc. 11001 Bren Road E. Minnetonka, MN 55343
PH: (952) 912-3444 or 877-912-3444
FX: (952) 912-4952