CSCI.4220 Network Programming
Fall, 2006
Class 2: Socket Programming in C

Clients and Servers

When two computers communicate on the Internet or any other network, one of the two is called the client and the other is called the server The client is the one that initiates the connection; thus, the client is analogous to the person who initiates a phone call or mails a letter. The other computer is called the server, analogous to the person who receives a phone call or receives a letter.

The server must be started first. Once a server is started, it goes to sleep waiting for clients to connect. Whenever a client connects, it wakes up, handles the request, and waits for the next client to connect. If handling the request is complex, a server might fork off a new thread or even a new process for each connection.

A server on Unix systems is typically run as a daemon. A daemon is a process which is not connected to a controlling terminal; it is running in background.

Note that the client needs to know about the existence of the server, but, until the connection is established, the server does not necessarily know about the existence of the client.

A single Internet host can run multiple different servers. One of the jobs of the TCP software is to multiplex incoming packets; that is, it has to determine the destination process. This is done with a port. A computer has 64K ports for TCP and an additional 64K ports for UDP.

In order for a client to establish a connection to a server, it needs to know the IP address of the server and the port number on which the application process is listening. Most computers on the internet have a name as well as an IP address. When you want to connect to www.amazon.com, you do not need to know that its IP address is 207.171.183.16. There is a fairly elaborate name service system on the Internet (which uses the same client server system) called DNS (the domain name server), so when an application has only a name, it can connect to a name server which will return the IP address.

Likewise, most people who use services on the Internet do not know anything about port numbers. The standard Internet services listen on standard port numbers. For example, a production web server always listens on TCP port 80.

A web server in a testing environment might listen on some other port. If you append a colon followed by a number at the end of a url, (for example, www.amazon.com:8080), this tells your browser (the client) to connect to a different port (8080 in the example), but of course you would only do this if you knew that there was a web server listening on that particular port.

Here are some other well known services and their port numbers

The lower 2000 ports are reserved by the kernel and require administrative privileges to use; the ports above this can be used by user processes.

Sockets

The mechanism that application programs use to communicate on a network is the socket. Sockets were first introduced in Unix BSD 4.1 (1982), and the popularity of this operating operating system among academics made the TCP/IP Internet protocol a standard (although the socket interface can handle other protocols as well). There is a series of Unix system calls that deal with sockets. The Win32 APIs for sockets are very similar.

Unix socket system calls

A socket is one end of a connection. The system call to create a socket is socket. Here is the function prototype.

   #include <sys/types.h>
   #include <sys/socket.h>

   int socket(int domain, int type, int protocol);

For an Internet socket the first argument, the domain, should be PF_INET, although the older form, AF_INET should also work. These two strings are defined as 2 in the header file sys/socket.h. There are other domains as well.

The second argument, the type, should be SOCK_STREAM to create a TCP socket, or SOCK_DGRAM to create a UDP socket. Recall that the TCP protocol sends a continuous stream of bytes to its application, which is why this is called a stream type.

The third argument should generally be zero, which means choose the default protocol (TCP for a stream socket).

The socket call returns a file descriptor if successful, and a negative number on failure. Failure is unlikely if your arguments are correct.

If you are unfamiliar with Unix system call failure, Go here

Here is the man page for socket

Both client processes and server processes use sockets and the socket system call, but the sequence of system calls after creating the socket is different for clients and for servers.

Socket system calls for servers

A server process first creates a socket using the socket system call. After a socket has been created, it must be bound to an address. The system call for this is bind.
int bind(int sock, struct sockaddr *addr, socklen_t addrlen)

The first argument is an open socket, the value returned from a socket system call. The second is a pointer to a socket address, and the third is the size of this address.

Here is a link to man page for bind

In the header file sys/socket.h the following structure is defined.

struct sockaddr {
    u_short sa_family;  /* address family: AF_xxx value */
    char sa_data[14];   /* up to 14 bytes of protocol specific address */
};

The type of the second field depends on the type of socket, so this is a Union. A union in C is a struct which can take on different forms.

For Internet addresses, we will use struct sock_addr_in. This has to contain the IP address and the port.

For internet addresses, the following structures are defined in the header file netinet/in.h.

struct in_addr {
    u_long s_addr;  /* 32-bit netid/hostid */
                    /* network byte ordered */
};

struct sock_addr_in {
    short sin_family;   /* AF_INET */
    u_short sin_port;   /* 16 bit port number */
                        /* network byte ordered */
    struct in_addr sin_addr;
    char sin_zero[8];   /* unused */
};
By now your eyes have certainly glazed over, but this is not as complicated as it seems. Here is some sample code which you can use to bind a server to port 8080. (The function error(char *) is a short function that you have to write which calls perror and then exits.)
1.   int sock, len, retval;
2.   unsigned short port;
3.   struct sockaddr_in server;
4.
5.   port = (unsigned short) 8080; 
6.   sock=socket(AF_INET, SOCK_STREAM, 0);
7.   if (sock < 0) error("Opening socket");
8.   server.sin_family=AF_INET;
9.   server.sin_addr.s_addr=INADDR_ANY; 
10.  server.sin_port=htons(port);  
11.  len=sizeof(server);
12.  retval = bind(sock, (struct sockaddr *)&server, len);
13.  if (retval < 0) error("binding");
This code creates a socket called sock. It then sets the fields of server. The symbolic constant INADDR_ANY in line 9 is used to refer to the internet address of the machine on which the process is running.

The function htons() at line 10 stands for host to network short. This function takes a short int (16 bit) as an argument, (which of course is in in host byte order) and returns the value in network byte order. The network is big-endian, so on a big-endian computer, this function simply returns its argument, but on a little endian computer (which includes Intel processors), it converts its argument to big endian and returns that value.

This is one of a family of four functions.

Once a socket is created and bound to an address, a server socket has to listen for connections. The system call for this is
listen
which takes two arguments. The first is a socket which is bound to an address, the second is the length of the backlog queue; note that this is not the number of connections that can be accepted, this is the number of connections that can be waiting to be accepted. In the old days, this had to be set to 5; on most modern systems, it usually doesn't matter what you set it to. If connections from clients are arriving faster than your server can accept them, the client receives a connection refused error.

Once a server is listening, it should enter an infinite loop to wait for clients to connect. The first (or at least one of the first) statements in this loop is a call to accept. Here is the function prototype.

     #include <sys/types.h>
     #include <sys/socket.h>

     int  accept(int s, struct sockaddr *addr, socklen_t *addrlen);
The accept system call takes three arguments. The first is the socket, the second is a pointer to a struct sockaddr, and the third is the size of a struct sockaddr. A call to accept will block until a client connects to the server. This will wake up the server. Accept returns an int, which is another socket. This is confusing, because the server listens on one socket, but when a connection from a client is established, all of the communication is on a different socket, the value of which is returned by accept. The second argument to accept will be set to the address of the client so that the server can know whom it is talking to.

Once a connection has been accepted, both sides can communicate on the new socket (the engineering term for this is full duplex). You can use read() and write() if you wish, but the preferred system calls are recv() for reading and send() for writing. These are similar to read and write except that they take a fourth argument, which allows you to set some flags. If you set the fourth argument to zero, they work identically to read and write.

Here are the function prototypes for send and recv:

   #include <sys/types.h>
   #include <sys/socket.h>

   ssize_t recv(int s, void *buf, size_t len, int flags);
   ssize_t send(int s, const void *msg, size_t len, int flags);
A ssize_t is a signed 32 bit integer and a size_t is an unsigned 32 bit integer on most machines. The return value is is the number of bytes read or written if the call was a success, 0 if the client has closed the socket, or a negative value if some other exception condition has occurred. The last argument, flags, should be set to zero.

As with read, a call to recv may not necessarily read the number of bytes requested, it will read the number of bytes available to read, up to the size of the buffer (which should be in len). However, a call to send should always send the number of bytes requested (the value in len) unless an exception occurs.

Here is a complete program for a very simple server.

/* server.c - creates a connection oriented (stream) Internet server
   for the Unix Operating system. Port is passed in as an argument
   To compile on solaris gcc ... -lnsl -lsocket */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h>
#include <arpa/inet.h>

#define BUFSIZE 1024
extern int errno;
void error(char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
     int sock, newsock, len, fromlen, n;
     unsigned short port;
     struct sockaddr_in server, from;
     char buffer[BUFSIZE];
     char *msg = "I Got your message";

     if (argc < 2) {
         fprintf(stderr,"usage %s portnumber\n",argv[0]);
         exit(0);
     }
     port = (unsigned short) atoi(argv[1]);
     sock=socket(AF_INET, SOCK_STREAM, 0);
     if (sock < 0) error("Opening socket");
     server.sin_family=AF_INET;
     server.sin_addr.s_addr=INADDR_ANY;
     server.sin_port=htons(port);  
     len=sizeof(server);
     if (bind(sock, (struct sockaddr *)&server, len) < 0) 
          error("binding socket");
     fromlen=sizeof(from);
     if (listen(sock,5) < 0) 
          error("listening");
     while (1) {
         newsock=accept(sock, (struct sockaddr *)&from, &fromlen);
         if (newsock < 0) error("Accepting");
         printf("A connection has been accepted from %s\n",
                 inet_ntoa((struct in_addr)from.sin_addr));
         n = recv(newsock,buffer,BUFSIZE-1,0);
         if (n < 1) {
	   error("Reading");
         }
         else {
           buffer[n]='\0';
           printf("Message from client is: %s\n",buffer);
           len = strlen(msg);
           n = send(newsock,msg,len,0);
           if (n < len) error("Error writing");
           if (close(newsock) < 0) error("closing");           
	 }
     } 
     return 0; // we never get here 
}

Download server.c here

This program creates a TCP socket in the Internet domain. It takes one argument, the port number that the server should be bound to. It binds the socket to that port on the local host (i.e. the machine that it is running on), listens for connections, and then enters an infinite loop. Whenever it accepts a new connection from a client, it reads a message from the client and displays it on the screen, sends a message back to the client, and closes the socket,

The only new function call in this program is inet_ntoa which takes one argument, an in_addr, (which is just a 32 bit unsigned int) and returns a string which is the IP address of its argument in dotted decimal form.

The Client

The client creates a socket just like the server. However, instead of binding to an address, it called the connect system call, which establishes a connection to a server. Here is the function prototype

#include <sys/types.h>
#include <sys/socket.h>

int  connect(int s, const struct sockaddr *name, int namelen);

You've probably already forgotten what a struct sockaddr is.

struct sockaddr {
    u_short sa_family;  /* address family: AF_xxx value */
    char sa_data[14];   /* up to 14 bytes of protocol specific address */
};
The contents of sa_data are interpreted according to the type of address. For Internet addresses, use
struct in_addr {
    u_long s_addr;  /* 32-bit netid/hostid */
                    /* network byte ordered */
};

struct sock_addr_in {
    short sin_family;   /* AF_INET */
    u_short sin_port;   /* 16 bit port number */
                        /* network byte ordered */
    struct in_addr sin_addr;
    char sin_zero[8];   /* unused */
};

You need to fill in the port number and the IP address of the server. Usually, you do not know the IP address, but you have the name of the computer. In this case, use the system call gethostbyname(). This takes one argument, a character string which is the name of the machine on which the server is running, and it returns a pointer to a struct hostent. This has a field , char *h_addr, which is the IP address. The size of this is in the field h_length

Aside If you have been paying attention, you might have noticed that an IP address, which is a 32 bit unsigned int, is considered a struct in_addr or a char *. You ought to find this confusing.

Here is a complete client. It takes two arguments, the name of the computer on which the server is running and the port number on which it is listening.

/* client.c    Creates Internet stream client for a Unix platform.  
   The name and port number of the server are passed in as arguments.
   To compile on solaris gcc ... -lnsl -lsocket
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> /* for atoi */

char *msg = "Hello from the client";
void error(char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
   int sock, n;
   unsigned short port;
   struct sockaddr_in server;
   struct hostent *hp;
   char buffer[1024];
   
   if (argc != 3) { 
         printf("Usage: %s server port\n", argv[0]);
         exit(1);
   }
   sock= socket(AF_INET, SOCK_STREAM, 0);
   if (sock < 0) error("Opening socket");

   server.sin_family = AF_INET;
   hp = gethostbyname(argv[1]);
   if (hp==NULL) error("Unknown host");
   memcpy((char *)&server.sin_addr,(char *)hp->h_addr,         
          hp->h_length);
   port = (unsigned short)atoi(argv[2]);
   server.sin_port = htons(port);
   if (connect(sock, (struct sockaddr *)&server, sizeof server) < 0)
             error("Connecting");
   n = send(sock, msg, strlen(msg),0);
   if (n < strlen(msg))
             error("Writing to socket");
   n = recv(sock, buffer, 1023,0);
   if (n < 1) error("reading from socket");
   buffer[n]='\0';
   printf("The message from the server is %s\n",buffer);
   if (close(sock) < 0) error("closing");
   printf("Client terminating\n");
   return 0;
}

You can download client.c here

If you are new to sockets, you should test these two programs before continuing, ideally on separate computers. Note that when you start up the server, nothing happens until it receives a connection.

A threaded server

If the server is going to do anything more complicated than sending a string back to the client, it should handle each connection in a separate thread (or sometimes even a separate process).

If you do not know much about threads, here is the man page for the function pthread_create, which creates a new thread.

Here is a server which creates a new thread for each connection

/* serverwiththread.c - creates a connection oriented (stream)
   socket in the Internet domain for the Unix Operating system
   Each connection is handled in a separate thread
   To compile on solaris gcc ... -lnsl -lsocket -lpthread
   To compile on freebsd gcc ... -pthread 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h> 
#include <stdlib.h>
#include <arpa/inet.h>
#include <pthread.h>

#define BUFSIZE 1024

extern int errno;
void error(char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
     int sock, *newsock, len, fromlen, retval;
     unsigned short port;
     struct sockaddr_in server;
     struct sockaddr_in from;
     pthread_t tid;
     void *ConnectionThread(void *); //function prototype

     if (argc < 2) {
         fprintf(stderr,"usage %s portnumber\n",argv[0]);
         exit(0);
     }
     port = (unsigned short) atoi(argv[1]);
     sock=socket(AF_INET, SOCK_STREAM, 0);
     if (sock < 0) error("Opening socket");
     server.sin_family=AF_INET;
     server.sin_addr.s_addr=INADDR_ANY;
     server.sin_port=htons(port);  
     len=sizeof(server);
     if (bind(sock, (struct sockaddr *)&server, len) < 0) 
          error("binding socket");
     fromlen=sizeof(from);
     if (listen(sock,5) < 0) 
          error("listening");;
     while (1) {
         newsock = (int *)malloc(sizeof (int));
         if (newsock == NULL) error("malloc");
         *newsock=accept(sock, (struct sockaddr *)&from, &fromlen);
         if (*newsock < 0) error("Accepting");
         printf("A connection has been accepted from %s\n",
                 inet_ntoa((struct in_addr)from.sin_addr));
         retval = pthread_create(&tid, NULL, ConnectionThread, (void *)newsock);
         if (retval != 0)   {
            error("Error, could not create thread");
         }
     } 
     return 0; // we never get here 
}

/****** ConnectionThread **********/
void *ConnectionThread(void *arg)
{
    int sock, n, len;
    char buffer[BUFSIZE];
    char *msg = "Got your message";
  
    sock = *(int *)arg;
    len  = strlen(msg);
    n = read(sock,buffer,BUFSIZE-1);
    while (n > 0) {
        buffer[n]='\0';
        printf("Message is %s\n",buffer);
        n = write(sock,msg,len);
        if (n < len) error("Error writing");
        n = read(sock,buffer,BUFSIZE-1);
        if (n < 0) error("Error reading");
    }
    if (close(sock) < 0) error("closing");
    pthread_exit(NULL);
    return NULL;
}

You can download serverwiththreads.c here

The syntax for passing the new file descriptor to the thread function requires explanation. The naive programmer might write code like this

/** bad code **/
int newsock;
...
while(1) {
      newsock=accept(sock, (struct sockaddr *)&from, &fromlen);
      if (newsock < 0) error("Accepting");
      retval = pthread_create(&tid, NULL, ConnectionThread, (void *)&newsock);
      ...
This bad code simply passes the address of newsock to the thread. Recall that threads run asynchronously, after the call to pthread_create, we do not know whether the main thread or the newly created thread will run first.

Suppose connections are arriving quickly and the main thread runs before the connection thread runs. The following sequence of events could occur.

  1. A connection is received from client A, the value of newsock is 5, an entry in the file descriptor table containing information about this newly established connection.
  2. A new thread is created, and the address of newsock is passed as an argument
  3. The main thread continues running; it returns to the start of the while loop and calls accept. Accept immediately returns with a connection from client B. The value of newsock is now 6, an entry in the file descriptor table containing information about the connection with client B.
  4. A new thread is created, the address of newsock is passed as an argument.
  5. The main thread continues running. It calls accept, but there are no new connections so accept blocks.
  6. The first connection thread wakes up, it is supposed to be reading from client A; its argument is the address of newsock, which is 6, the file descriptor for client B. Thus the reads and writes which should be for client A go to client B

The above program avoids this problem by allocating new memory for each socket with malloc. This is somewhat inefficient, so an alternative would be to maintain an array of sockets in the program.

Datagram sockets

Recall that there are are two widely used protocols for the transport layer TCP and UDP. Stream sockets as described above use TCP; the connection is established prior to any data being transmitted, and the TCP software assures that the bytes are reliably delivered to the process in a stream in the order that they were sent. When speed is more important than reliability, a program should use the UDP protocol instead.

A socket which uses UDP is called a datagram socket. A datagram is connectionless and unreliable. It is simply a packet sent over the Internet on a best effort basis, with no acknowledgements or other reliability checks. The advantage of UDP is that it is much more efficient, and so for short requests, a time of day server for example, UDP is often used. UDP is also used for distributed file system requests which are typically on a LAN with very high reliability, and where performance is extremely important.

A server for UDP sockets uses the same system calls as the TCP server with the following differences.

Here is a complete program which creates a UDP server. It listens on port 51717.

/* This program creates a datagram server process 
   in the internet domain.  it listens on port
   51717.   On solaris, compile like this
   gcc -g -Wall server.udp.c -lnsl -lsocket */
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<stdio.h>
#include<strings.h>
#include<arpa/inet.h> 
#define BUFSIZE 1024

void error(char *);
int main()
{
   int sock, length, fromlen, n;
   struct sockaddr_in server;
   struct sockaddr_in from;
   char buf[BUFSIZE];

   sock=socket(AF_INET, SOCK_DGRAM, 0);
   if (sock < 0)
       error("Opening socket");
   length = sizeof(server);
   bzero(&server,length);
   server.sin_family=AF_INET;
   server.sin_addr.s_addr=INADDR_ANY;
   server.sin_port=htonl(51717);
   if (bind(sock,(struct sockaddr *)&server,length)<0) 
       error("binding"); 
   while (1) {
       n = recvfrom(sock,buf,BUFSIZE,0,(struct sockaddr *)&from,&fromlen);
       if (n < 0) error("recvfrom");
       buf[n]='\0';
       printf("The message from %s is %s\n",
            inet_ntoa((struct in_addr)from.sin_addr), buf);
       n = sendto(sock,"Got your message",16,0,(struct sockaddr *)&from,fromlen);
       if (n < 0) error("sendto");
   }
   return 0;
 }

void error(char *msg)
{
    perror(msg);
    exit(0);
}

Download udpserver.c here

You could probably write a udp client by yourself, but here it is. The server name and port number are passed in as arguments.

/* Datagram client in the internet domain */
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<stdio.h>
#include<strings.h>
#include<stdlib.h>
#define DATA "I love operating systems ..."
#define BUFSIZE 1024 

void error(char *);
int main(int argc, char *argv[])
{
   int sock, length, n;
   struct in_addr *hostaddr;
   struct sockaddr_in server;
   struct hostent *hp, *gethostbyname();
   char buf[BUFSIZE];

   
   if (argc != 3) { 
         printf("Usage: server port\n");
         exit(1);
   }
   sock= socket(AF_INET, SOCK_DGRAM, 0);
   if (sock < 0) error("socket");

   server.sin_family = AF_INET;

   hp = gethostbyname(argv[1]);
   if (hp==0) error("Unknown host");

   hostaddr =(struct in_addr *) hp->h_addr;
   bcopy((char *)hostaddr, 
        (char *)&server.sin_addr,
         hp->h_length);
   server.sin_port = htonl(atoi(argv[2]));
   length=sizeof(struct sockaddr_in);
   n=sendto(sock,DATA,30,0,(struct sockaddr *)&server,length);
   if (n < 0) perror("Sendto");
   n = recvfrom(sock,buf,BUFSIZE,0,(struct sockaddr *) &server,&length);
   if (n < 0) error ("recvfrom");
   buf[n]='\0';
   printf("The return message was %s\n",buf);
   return 0;
}

void error(char *msg)
{
    perror(msg);
    exit(0);
}

Download udpclient.c here

Sockets on Windows

Socket programming on windows uses exactly the same system calls as Unix, with just a few annoying quirks (but you could have guessed that!). The header files are completely different. Almost all windows programs require windows.h and you need to include winsock.h for the socket stuff.

In order to use sockets on windows, the program have to initiate the Winsock dynamic link library WS2_32.DLL. This is done with a call to WSAStartup. This takes two arguments, WORD wVersionRequested and a pointer to a WSADATA structure. Rather than try to explain this, I'll just give you the code. This has to appear in any program which uses winsock prior to any calls to the socket APIs.

#include <winsock.h>
int retval;
WORD version;
WSADATA stWSAData;
...
version = MAKEWORD(2,2);
retval = WSAStartup(version, &stWSAData);
if (retval != 0) error(...)

Here is a link to the online help for WSAStartup.

Windows has no concept of a file descriptor, so the socket system call returns a value of type SOCKET. The accept call also returns a type SOCKET. You have to use the closesocket system call instead of the close system call.

Finally, you need to link to the winsock library during the compile. Here is how you do this:

Here is the server code for a stream socket using winsock.

/* This program creates a tcp server process in the 
   internet domain, port is passed in as an arg */
/* to compile, add wsock32.lib to the list of
   libraries to link with in the project settings menu*/
#include<windows.h>
#include<stdio.h>
#include<winsock.h>

#define BUFSIZE 1024
char *msg = "I got your message";

void error(char *msg)
{
	printf("ERROR, %s, errno is %d\n",msg, WSAGetLastError());
	exit(0);
}

int main(int argc, char *argv[])
{
   SOCKET sock, newsock;
   int len, fromlen;
   DWORD n, retval;
   unsigned short port;
   struct sockaddr_in server;
   struct sockaddr_in from;
   char buffer[BUFSIZE];
   WORD version;
   WSADATA stWSAData;

   if (argc < 2) {
     fprintf(stderr,"usage %s portnumber\n",argv[0]);
     exit(0);
   }
   version = MAKEWORD(2,2);
   retval =WSAStartup(version,&stWSAData);
   if (retval != 0) error("WSAStartup");
   port = (unsigned short) atoi(argv[1]);
   sock=socket(AF_INET, SOCK_STREAM, 0);
   if (sock == INVALID_SOCKET) error("Opening socket");
   server.sin_family=AF_INET;
   server.sin_addr.s_addr=INADDR_ANY;
   server.sin_port=htons(port);  
   len=sizeof(server);
   if (bind(sock,
           (struct sockaddr *)&server, 
           len) != 0) 
        error("binding socket");
   fromlen=sizeof(from);
   listen(sock,5);
   while (1) {
        newsock=accept(sock,
                  (struct sockaddr *)&from, 
                  &fromlen);
        printf("A connection has been accepted\n");

            n = recv(newsock,buffer,BUFSIZE,0);
            if (n < 1) {
	        error("Reading from socket");
            }
             else {
	        buffer[n]='\0';
                printf("The message from %s is %s\n",
                  inet_ntoa(from.sin_addr),
                  buffer);
	     }
	     n = send(newsock, msg, strlen(msg),0);
	     if (n != strlen(msg)) error("Writing");
         closesocket(newsock); 
	}
   return 0; /* we never get here */
}

Download winserver.c here

Here are the Unix man pages for the functions discussed in this module
socket
bind
listen
accept
htons, htonl, ntohs, nohl
inet_ntoa and related functions which manipulate IP addresses
connect
recv, recvfrom
send, sendto

Here is a link to the online help pages for Win32 Sockets

Here is a link to the pthread calls for Unix

Here is the online help for the windows CreateThread call

Click here if you want to learn more about threads in Windows