UNIX vs Windows Sockets

UNIX vs Windows Sockets
To demonstrate the key differences, we perform a side-by-side comparison between the UNIX and adapted Windows Socket code. We break the programs into separate sections, each of which deals with a specific difference. Comments have been removed from the programs to allow focus on the key differences.

 


UNIX
Windows
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>

Header File

Header files needed by Windows socket programs are slightly different than UNIX socket programs. For windows socket programming you need to add the winsock.h header file to your programs. Since this file includes all socket definitions and prototypes, several of the header files from the UNIX example are not needed.
UNIX
Windows
#define RCVBUFSIZE 32
void DieWithError(char *errorMessage);
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in echoServAddr;
unsigned short echoServPort;
char *servIP;
char *echoString;
char echoBuffer[RCVBUFSIZE];
unsigned int echoStringLen;
int bytesRcvd, totalBytesRcvd;
if ((argc < 3) || (argc > 4))
{
fprintf(stderr, “Usage: %s
<Server IP> <Echo Word>
[<Echo Port>]n”,argv[0]);
exit(1);
 
}
servIP = argv[1];
echoString = argv[2];
if (argc == 4)
echoServPort = atoi(argv[3]);
else

echoServPort = 7;

#define RCVBUFSIZE 32
void DieWithError(char *errorMessage);
void main(int argc, char *argv[])
{
int sock;
struct sockaddr_in echoServAddr;
unsigned short echoServPort;
char *servIP;
char *echoString;
char echoBuffer[RCVBUFSIZE];
int echoStringLen;
int bytesRcvd, totalBytesRcvd;
WSADATA wsaData;
if ((argc < 3) || (argc > 4))
{
fprintf(stderr, “Usage: %s
<Server IP> <Echo Word>
[<Echo Port>]n”,argv[0]);
exit(1);
}
servIP = argv[1];
echoString = argv[2];
if (argc == 4)
echoServPort = atoi(argv[3]);
else
echoServPort = 7;
if (WSAStartup(MAKEWORD(2, 0),
&wsaData) != 0)
{
fprintf(stderr,”WSAStartup()
failed”);
exit(1);

}

 

Application Setup
The setup of the application is identical except for initialization code required by WinSock. The WinSock library is initialized by WSAStartup( ). The first parameter to the startup function is the version of WinSock the program wishes to use. We want version 2.0. MAKEWORD(2, 0) returns the version (2.0) number in the format expected by the startup function. The second parameter is a pointer to a WSADATA structure that allows the WinSock library to communicate critical information to the program such as limits on the number of sockets that can be created. WSAStartup( ) fills in the WSADATA structure before returning.
typedef struct WSAData {
WORD wVersion;
WORD wHighVersion;
char szDescription[WSADESCRIPTION_LEN+1];
char szSystemStatus[WSASYS_STATUS_LEN+1];
unsigned short iMaxSockets;
unsigned short iMaxUdpDg;
char FAR * lpVendorInfo;
} WSADATA;
WSAStartup( ) returns a zero on success or a non-zero number on failure.
 

 
UNIX and Windows
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError(“socket() failed”);
memset(&echoServAddr, 0, sizeof(echoServAddr));
echoServAddr.sin_family = AF_INET;
echoServAddr.sin_addr.s_addr = inet_addr(servIP);
echoServAddr.sin_port = htons(echoServPort);
if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
DieWithError(“connect() failed”);
echoStringLen = strlen(echoString);
if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
DieWithError(“send() sent a different number of bytes than expected”);
totalBytesRcvd = 0;
printf(“Received: “);
while (totalBytesRcvd < echoStringLen)
{
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE – 1, 0)) <= 0)
DieWithError(“recv() failed or connection closed prematurely”);
totalBytesRcvd += bytesRcvd;
echoBuffer[bytesRcvd] = ”;
printf(echoBuffer);
}
printf(“n”);

 

Communication

The communication portion of the UNIX and Windows programs is identical.

UNIX
Windows
close(sock);
exit(0);
}
closesocket(sock);
WSACleanup();
exit(0);
}

 

Application Shutdown
The shutdown of the application differs slightly between UNIX and Windows. Instead of close( ), WinSock uses closesocket( ); however, the two functions do the same thing so the difference is in name only. Finally, we must use WSACleanup( ) to deallocate the resources used by Winsock. WSACleanup( ) returns a zero on success and a non-zero number on failure.
WinSock Error Reporting
Windows uses its own error message facility to indicate what went wrong with a Sockets call. WSAGetLastError( ) returns an integer representing the last error that occurred. If a WinSock application needs to know why a socket call failed, it should call WSAGetLastError( ) immediately after the failed socket call. As you might expect, our error reporting function, DieWithError( ) must be changed to work under Windows.

UNIX
Windows
#include <stdio.h>
#include <stdlib.h>
void DieWithError(char *errorMessage)
{
perror(errorMessage);
exit(1);
}
#include <stdio.h>
#include <winsock.h>
#include <stdlib.h>
void DieWithError(char *errorMessage)
{
fprintf(stderr,”%s: %dn”,
errorMessage, WSAGetLastError());
exit(1);
}

 

 

DieWithError( )
The Windows version of DieWithError( ) uses WSAGetLastError( ) instead of perror to report system error messages.
 
Conclusion
Moving from UNIX sockets to Windows sockets is fairly simple. Windows programs require a different set of include files, need initialization and deallocation of WinSock resources, use closesocket( ) instead of close(), and use a different error reporting facility. However, the meat of the application is identical to UNIX.

Comments