Silvio's blog

Berkeley Socket API – Creating a TCP/IP Server in C

Programming Languages

C

API

Berkeley Socket API

What are sockets?

“In computer networking, an Internet socket (or commonly, a network socket or socket) is the endpoint of a bidirectional inter-process communication flow across an Internet Protocol-based computer network, such as the Internet. Internet sockets (in plural) are an application programming interface (API) application program and the TCP/IP stack, usually provided by the operating system. Internet sockets constitute a mechanism for delivering incoming data packets to the appropriate application process or thread, based on a combination of local and remote IP addresses and port numbers. Each socket is mapped by the operational system to a communicating application process or thread.”

in Wikipedia

Data Structure used to store socked details

struct sockaddr_in6 {
	u_char		sin6_len;	// length of this structure
	u_char		sin6_family;	// AF_INET6
	u_int16m_t	sin6_port;	// Transport layer port #
	u_int32m_t	sin6_flowinfo;	// IPv6 flow information
	struct in6_addr	sin6_addr;	// IPv6 address
};

Data Structure used to store a time value

Used on ’select’ for timeouts

struct sockaddr_in6 {
     long int tv_sec      // This represents the number of whole seconds of elapsed time.
     long int tv_usec    //  The rest of the elapsed time (microseconds)
};

Filling the socket address

struct sockaddr_in6 socketaddress;

memset(&socketaddress,0,sizeof(socketaddress));	// Fill the structure with zero's
socketaddress.sin6_addr = in6addr_any;		// Listen on any ipv6 address
socketaddress.sin6_family = AF_INET6;		// Address Family AF_INET6 is required
socketaddress.sin6_port = htons(8000);		// Listen on port 8000, we have to convert the integer to network short

Creating the socket

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

domain

AF_UNIX – UNIX internal protocols
AF_INET – ARPA Internet protocols
AF_ISO – ISO protocols
AF_NS – Xerox Network Systems protocols
AF_IMPLINK – IMP host at IMP link layer

Type

SOCK_STREAM – provides sequenced, reliable, two-way connection based byte streams
SOCK_DGRAM – connectionless, unreliable messages of a fixed (typically small) maximum length
SOCK_RAW – sockets provide access to internal network protocols and interfaces
SOCK_SEQPACKET – provide a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length
SOCK_RDM – Not implemented

Returns

0 – Error
1+ – Socket descriptor

Bind the socket

int bind(int socket, const struct sockaddr *address, socklen_t address_len);

socket – Socket descriptor
address – Socket address (address, port, family…)
address_len – Structure address size

Listen on socket

int listen(int socket, int backlog);

socket – Socket descriptor
backlog – Maximum pending connections on queue

Returns

0 – OK
-1 – Error

Wait for socket to be ready

int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout);

ndfs – number of descriptors
readfds – ’set’ of descriptors to read from
writefds – ’set’ of descriptors to write to
errorfds – ’set’ of descriptors to expect errors from
timeout – time to wait before giveout a timeout

Returns

1+ – Socket descriptor
0 – Timeout
-1 – Error

Accepting an incoming connection

int accept(int socket, struct sockaddr *restrict address, socklen_t *restrict address_len);

socket – Socket descriptor
address – Socket address (address, port, family…)
address_len – Structure address size

Returns

1+ – Descriptor of the new socket
-1 – Error

Read and write from a socket

It works exactly like when we’re reading from a file, pipe, etc.

Read from socket

read(sockd, &buffer, 100);

Write to socket

write(sockd, &buffer, strlen(buffer));

The server code revealed

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>

void newConnectionHandler(int sockd){
        char buffer[100];
        if(read(sockd, &buffer, 100) < 1)
                perror("Unable to read from socket");
        if(write(sockd, &buffer, strlen(buffer)) < 1)
                perror("Unable to write on socket");
}

int main(int argc, char *argv[])
{
        int sockd,newsockd,tmpint;
        struct sockaddr_in6 socketaddress;
        fd_set descriptorslist;
        struct timeval timeout;

        memset(&socketaddress,0,sizeof(socketaddress));
        socketaddress.sin6_addr = in6addr_any;
        socketaddress.sin6_family = AF_INET6;
        socketaddress.sin6_port = htons(8000);

        // Create the socket - inet6 - stream - tcp
        if((sockd = socket(AF_INET6, SOCK_STREAM,0))<1){
                perror("Unable to create socket");
                return 1;
        }

        // Bind socket sockfd on socketaddress
        if(bind(sockd, (struct sockaddr *)&socketaddress, sizeof(socketaddress)) != 0){
                perror("Unable to bind socket");
                return 1;
        }
        // Listen on socket, queue up to 10 connections
        if(listen(sockd,10) != 0){
                perror("Unable to listen on socket ");
                return 1;
        }

        // Clear the socket 'set'
        FD_ZERO(&descriptorslist);

        // Add sockd to fdread 'set'
        FD_SET(sockd, &descriptorslist);

        while(1){
                // Set socket timeout to 1.1secs, timeout values change after each select so it has to be inside the loop
                timeout.tv_sec = 1;
                timeout.tv_usec = 100;
                switch(select(32, &descriptorslist, NULL, NULL, &timeout)){
                        case -1:
                                perror("And error has ocurred");
                                break;
                        case 0:
                                printf("Timeout");
                                break;
                        default:
                                // Default, more than 0, number of descriptors on 'descriptorslist' ready
                                tmpint = sizeof(socketaddress);
                                // We fork an handler for the new connection (a new socket is passed as argument)
                                if(fork() == 0) // The above line is executed on child, where fork() == 0
                                {
                                        newConnectionHandler(accept(sockd,(struct sockaddr *)&socketaddress, &tmpint));
                                        exit(0);
                                }
                }
        }
}
Pages (8): « First ... « 1 2 3 4 5 6 7 » ... Last »
Your Ads Here
Promote your products