| Tenouk.com |< Winsock Program Example 3 | Main | Winsock Program Example 5 >| Site Index | Download |
WINSOCK 2
WINDOWS SOCKET: PROGRAM EXAMPLES PART 4
|
|
|
|
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 the basic of networking such as 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.
Sending and Receiving Data
The following code demonstrates the send() and recv() functions (TCP packet). For server program:
int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[200] = "Hello! I’m server, sending some test data."; char recvbuf[200] = "";
bytesRecv = recv(m_socket, recvbuf, 32, 0); printf("Bytes Recv: %ld\n", bytesRecv);
bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); printf("Bytes Sent: %ld\n", bytesSent);
For client program:
int bytesSent; int bytesRecv = SOCKET_ERROR; char sendbuf[200] = "Hello! I’m client, sending some test data."; char recvbuf[200] = "";
bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0); printf("Bytes Sent: %ld\n", bytesSent);
while(bytesRecv == SOCKET_ERROR) { bytesRecv = recv(m_socket, recvbuf, 32, 0); if (bytesRecv == 0 || bytesRecv == WSAECONNRESET) { printf("Connection Closed.\n"); break; } if (bytesRecv < 0) return; printf("Bytes Recv: %ld\n", bytesRecv); }
In this code, two integers are used to keep track of the number of bytes that are sent and received. The send() and recv() functions both return an integer value of the number of bytes sent or received, respectively, or an error. Each function also takes the same parameters: the active socket, a char buffer, and the number of bytes to send or receive, and any flags to use. Use recvfrom() and sendto() functions for the connectionless socket such as for the User Datagram Protocol (UDP). The following is our complete send, receive and read data for the client and server program examples. Firstly we run the server program to listen for connection.
Program Example
// Microsoft Development Environment 2003 - Version 7.1.3088 // Copyright (r) 1987-2002 Microsoft Corporation. All Right Reserved // Microsoft .NET Framework 1.1 - Version 1.1.4322 // Copyright (r) 1998-2002 Microsoft Corporation. All Right Reserved // // Run on Windows XP Pro machine, version 2002, SP 2 // // <windows.h> already included // WINVER = 0x0501 for Xp already defined in windows.h // Server program, using TCP
|
|
|
|
#include <stdio.h>
#include <winsock2.h>
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
// Using MAKEWORD macro, Winsock version request 2.2
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0)
{
/* Tell the user that we could not find a usable */
/* WinSock DLL.*/
printf("Server: The Winsock dll not found!\n");
return 0;
}
else
{
printf("Server: The Winsock dll found!\n");
printf("Server: The status: %s.\n", wsaData.szSystemStatus);
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )
{
/* Tell the user that we could not find a usable */
/* WinSock DLL.*/
printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
WSACleanup();
return 0;
}
else
{
printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
//////////Create a socket////////////////////////
//Create a SOCKET object called m_socket.
SOCKET m_socket;
// Call the socket function and return its value to the m_socket variable.
// For this application, use the Internet address family, streaming sockets, and
// the TCP/IP protocol.
// using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Check for errors to ensure that the socket is a valid socket.
if (m_socket == INVALID_SOCKET)
{
printf("Server: Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else
{ printf("Server: socket() is OK!\n"); }
////////////////bind//////////////////////////////
// Create a sockaddr_in object and set its values.
sockaddr_in service;
// AF_INET is the Internet address family.
service.sin_family = AF_INET;
// "127.0.0.1" is the local IP address to which the socket will be bound.
service.sin_addr.s_addr = inet_addr("127.0.0.1");
// 55555 is the port number to which the socket will be bound.
service.sin_port = htons(55555);
// Call the bind function, passing the created socket and the sockaddr_in structure as parameters.
// Check for general errors.
if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("Server: bind() failed: %ld.\n", WSAGetLastError());
closesocket(m_socket);
return 0;
}
else
{
printf("Server: bind() is OK!\n");
}
// Call the listen function, passing the created socket and the maximum number of allowed
// connections to accept as parameters. Check for general errors.
if (listen(m_socket, 10) == SOCKET_ERROR)
printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError());
else
{
printf("Server: listen() is OK, I'm waiting for connections...\n");
}
// Create a temporary SOCKET object called AcceptSocket for accepting connections.
SOCKET AcceptSocket;
// Create a continuous loop that checks for connections requests. If a connection
// request occurs, call the accept function to handle the request.
printf("Server: Waiting for a client to connect...\n" );
printf("***Hint: Server is ready...run your client program...***\n");
// Do some verification...
while (1)
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(m_socket, NULL, NULL);
}
// else, accept the connection...
// When the client connection has been accepted, transfer control from the
// temporary socket to the original socket and stop checking for new connections.
printf("Server: Client Connected!\n");
m_socket = AcceptSocket;
break;
}
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[200] = "This string is a test data from server";
// initialize to empty data...
char recvbuf[200] = "";
// Send some test string to client...
printf("Server: Sending some test data to client...\n");
bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0);
if (bytesSent == SOCKET_ERROR)
printf("Server: send() error %ld.\n", WSAGetLastError());
else
{
printf("Server: send() is OK.\n");
printf("Server: Bytes Sent: %ld.\n", bytesSent);
}
// Receives some test string from client...and client
// must send something lol...
bytesRecv = recv(m_socket, recvbuf, 200, 0);
if (bytesRecv == SOCKET_ERROR)
printf("Server: recv() error %ld.\n", WSAGetLastError());
else
{
printf("Server: recv() is OK.\n");
printf("Server: Received data is: \"%s\"\n", recvbuf);
printf("Server: Bytes received: %ld.\n", bytesRecv);
}
WSACleanup();
return 0;
}

Figure 1
The server program is listening to and waiting for connection. Next we run the following client program.
Program Example
// Microsoft Development Environment 2003 - Version 7.1.3088
// Copyright (r) 1987-2002 Microsoft Corporation. All Right Reserved
// Microsoft .NET Framework 1.1 - Version 1.1.4322
// Copyright (r) 1998-2002 Microsoft Corporation. All Right Reserved
//
// Run on Windows XP Pro machine, version 2002, SP 2
//
// <windows.h> already included
// WINVER = 0x0501 for Xp already defined in windows.h
// A sample of client program using TCP
#include <stdio.h>
#include <winsock2.h>
int main()
{
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
printf("Client: Error at WSAStartup().\n");
else
printf("Client: WSAStartup() is OK.\n");
// Create a socket.
SOCKET m_socket;
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET)
{
printf("Client: socket() - Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else
printf("Client: socket() is OK.\n");
// Connect to a server.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
// Just test using the localhost, you can try other IP address
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(55555);
if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
printf("Client: connect() - Failed to connect.\n");
WSACleanup();
return 0;
}
else
{
printf("Client: connect() is OK.\n");
printf("Client: Can start sending and receiving data...\n");
}
// Send and receive data.
int bytesSent;
int bytesRecv = SOCKET_ERROR;
// Be careful with the array bound, provide some checking mechanism...
char sendbuf[200] = "This is a test string from client";
char recvbuf[200] = "";
// Receives some test string to server...
while(bytesRecv == SOCKET_ERROR)
{
bytesRecv = recv(m_socket, recvbuf, 200, 0);
if (bytesRecv == 0 || bytesRecv == WSAECONNRESET)
{
printf("Client: Connection Closed.\n");
break;
}
if (bytesRecv < 0)
return 0;
else
{
printf("Client: recv() is OK.\n");
printf("Client: Received data is: \"%s\"\n", recvbuf);
printf("Client: Bytes received is: %ld.\n", bytesRecv);
}
}
// Sends some test data to server...
bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0);
if(bytesSent == SOCKET_ERROR)
printf("Client: send() error %ld.\n", WSAGetLastError());
else
{
printf("Client: send() is OK - Bytes sent: %ld\n", bytesSent);
printf("Client: The test string sent: \"%s\"\n", sendbuf);
}
WSACleanup();
return 0;
}

Figure 2
And the previous server console output is shown below that complete the server-client communication.

Figure 3
Try running the client program from different machines and change the server IP address accordingly. Another more flexible client-server program example is given at the end of this note.
Notes for ATM
The following are important issues associated with connection setup, and must be considered when using Asynchronous Transfer Mode (ATM) with Windows Sockets 2:
▪ The accept() and WSAAccept() functions do not necessarily set the remote address and address length parameters. Therefore, when using ATM, the caller should use the WSAAccept() function and place ATM_CALLING_PARTY_NUMBER_IE in the ProviderSpecific member of the QOS structure, which itself is included in the lpSQOS parameter of the callback function used in accordance with WSAAccept().
▪ When using the accept() function, realize that the function may return before connection establishment has traversed the entire distance between sender and receiver. This is because the accept() function returns as soon as it receives a CONNECT ACK message; in ATM, a CONNECT ACK message is returned by the next switch in the path as soon as a CONNECT message is processed (rather than the CONNECT ACK being sent by the end node to which the connection is ultimately established). As such, applications should realize that if data is sent immediately following receipt of a CONNECT ACK message, data loss is possible, since the connection may not have been established all the way between sender and receiver.
connect()
|
Item |
Description |
|
Function |
connect(). |
|
Use |
Establishes a connection to a specified socket. |
|
Prototype |
int connect(SOCKET s, const struct sockaddr* name, int namelen); |
|
Parameters |
s [in] Descriptor identifying an unconnected socket.
name [in] Name of the socket in the sockaddr structure to which the connection should be established.
namelen [in] Length of name, in bytes. |
|
Return value |
See below. |
|
Include file |
<winsock2.h> |
|
Library |
ws2_32.lib |
|
Remark |
See below. |
|
Table 1 |
|
Return Values
If no error occurs, connect() returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError(). On a blocking socket, the return value indicates success or failure of the connection attempt. With a non-blocking socket, the connection attempt cannot be completed immediately. In this case, connect() will return SOCKET_ERROR, and WSAGetLastError() will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:
▪ Use the select() function to determine the completion of the connection request by checking to see if the socket is writeable.
▪ If the application is using WSAAsyncSelect() to indicate interest in connection events, then the application will receive an FD_CONNECT notification indicating that the connect operation is complete (successfully or not).
▪ If the application is using WSAEventSelect() to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
Until the connection attempt completes on a non-blocking socket, all subsequent calls to connect() on the same socket will fail with the error code WSAEALREADY, and WSAEISCONN when the connection completes successfully. Due to ambiguities in version 1.1 of the Windows Sockets specification, error codes returned from connect() while a connection is already pending may vary among implementations. As a result, it is not recommended that applications use multiple calls to connect() to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error values the same way that they handle WSAEALREADY, to assure robust execution. If the error code returned indicates the connection attempt failed (that is, WSAECONNREFUSED, WSAENETUNREACH, WSAETIMEDOUT) the application can call connect() again for the same socket.
|
Error code |
Meaning |
|
WSANOTINITIALISED |
A successful WSAStartup() call must occur before using this function. |
|
WSAENETDOWN |
The network subsystem has failed. |
|
WSAEADDRINUSE |
The socket's local address is already in use and the socket was not marked to allow address reuse with SO_REUSEADDR. This error usually occurs when executing bind(), but could be delayed until this function if the bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be committed at the time of this function. |
|
WSAEINTR |
The blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall(). |
|
WSAEINPROGRESS |
A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. |
|
WSAEALREADY |
A non-blocking connect call is in progress on the specified socket. In order to preserve backward compatibility, this error is reported as WSAEINVAL to Windows Sockets 1.1 applications that link to either Winsock.dll or Wsock32.dll. |
|
WSAEADDRNOTAVAIL |
The remote address is not a valid address (such as ADDR_ANY). |
|
WSAEAFNOSUPPORT |
Addresses in the specified family cannot be used with this socket. |
|
WSAECONNREFUSED |
The attempt to connect was forcefully rejected. |
|
WSAEFAULT |
The name or the namelen parameter is not a valid part of the user address space, the namelen parameter is too small, or the name parameter contains incorrect address format for the associated address family. |
|
WSAEINVAL |
The parameter s is a listening socket. |
|
WSAEISCONN |