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 7).
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_DGRAM
and
Protocol
is IPPROTO_UDP
for a
blocking, connectionless datagram 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 WSASendTo
, 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 UDP, 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
UDP 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
UDP Client destination address information.
4. Transmit data
Transmitting data is done by calling
WSASendTo
.
WSASendTo(Socket, &WSABuf,
1, &LengthSent,
0, &SockAddr, sizeof(SockAddr),
NULL, NULL);
To simplify transmitting data, and to hide many of the details
associated with the parameters necessary to call
WSASendTo
, this sample uses its own function named
MySocketSendTo
.
MySocketSendTo(MySocket, SendData, sizeof(SendData),
AddressToSendTo, PortToSendTo);
The 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,
SendLength
which is the number of bytes
SendData
points to, and
AddressToSendTo
and
PortToSendTo
which provide the IP address and
port number of the device server to send the data to. For Digi
device servers, the UDP port number for Port 1 is
2101
5. Receive data
To retrieve data received at the local address, call
WSARecvFrom
.
WSARecvFrom(Socket, &WSABuf, 1, Length,
&Flags, &SockAddr, &SockAddrLength,
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 WSASendTo
, WSARecvFrom
has a
large number of parameters, providing great flexibility at the
price of adding to its complexity. Also like
WSASendTo
, the sample provides an alternative
function, MySocketRecvFrom
that is somewhat
easier to use.
MySocketRecvFrom(MySocket,
RecvData, &BytesReceived,
AddressReceivedFrom,
&AddressReceivedFromLength);
The caller to MySocketRecv
need only supply the
prerequisite MySocket
, a buffer
RecvData
to hold the received data,
BytesReceived
which specifies the length of
RecvData
and on return exactly how many bytes were
actually copied into the buffer,
AddressReceivedFrom
which provides space to
return a string representation of the IP address and port number of
the device server that sent the data, and
&AddressReceivedFromLength
which specifies
the length of AddressReceivedFrom
.
6. Close the 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
).
7. Cleanup
Before exiting the program, call:
WSACleanup();
For every successful call to WSAStartup
an
application completes, the application must make one call to
WSACleanup
.