BSD Sockets programming in C

Author: Svetoslav P. Chukov 

int accept (int socket, struct sockaddr *addr, socklen_t *length_ptr)
This function is used to accept a connection request on the server socket socket. The accept function waits if there are no connections pending, unless the socket socket has nonblocking mode set. (You can use select to wait for a pending connection, with a nonblocking socket.) See File Status Flags, for information about nonblocking mode.

The addr and length-ptr arguments are used to return information about the name of the client socket that initiated the connection. See Socket Addresses, for information about the format of the information.

Accepting a connection does not make socket part of the connection. Instead, it creates a new socket which becomes connected. The normal return value of accept is the file descriptor for the new socket.

After accept, the original socket socket remains open and unconnected, and continues listening until you close it. You can accept further connections with socket by calling accept again.

If an error occurs, accept returns -1.

int bind (int socket, struct sockaddr *addr, socklen_t length)
The bind function assigns an address to the socket socket. The addr and length arguments specify the address; the detailed format of the address depends on the namespace. The first part of the address is always the format designator, which specifies a namespace, and says that the address is in the format of that namespace.

The return value is 0 on success and -1 on failure.

int connect (int socket, struct sockaddr *addr, socklen_t length)
The connect function initiates a connection from the socket with file descriptor socket to the socket whose address is specified by the addr and length arguments. (This socket is typically on another machine, and it must be already set up as a server.) See Socket Addresses, for information about how these arguments are interpreted.

Normally, connect waits until the server responds to the request before it returns. You can set nonblocking mode on the socket socket to make connect return immediately without waiting for the response. See File Status Flags, for information about nonblocking mode.

The normal return value from connect is 0. If an error occurs, connect returns -1.

uint16_t htons (uint16_t hostshort)
This function converts the uint16_t integer hostshort from host byte order to network byte order.

uint32_t htonl (uint32_t hostlong)
This function converts the uint32_t integer hostlong from host byte order to network byte order.

This is used for IPv4 Internet addresses.

int listen (int socket, unsigned int n)
The listen function enables the socket socket to accept connections, thus making it a server socket.

The argument n specifies the length of the queue for pending connections. When the queue fills, new clients attempting to connect fail with ECONNREFUSED until the server calls accept to accept a connection from the queue.

The listen function returns 0 on success and -1 on failure.

int read (int socket, void *buffer, size_t size)
If nonblocking mode is set for socket, and no data are available to be read, read fails immediately rather than waiting. See File Status Flags, for information about nonblocking mode.

This function returns the number of bytes received, or -1 on failure.

int send (int socket, void *buffer, size_t size, int flags)
The send function is like write, but with the additional flags flags. The possible values of flags are described in Socket Data Options.

This function returns the number of bytes transmitted, or -1 on failure. If the socket is nonblocking, then send (like write) can return after sending just part of the data. See File Status Flags, for information about nonblocking mode.

Note, however, that a successful return value merely indicates that the message has been sent without error, not necessarily that it has been received without error.

int shutdown (int socket, int how)
The shutdown function shuts down the connection of socket socket. The argument how specifies what action to perform:


 * 0 - Stop receiving data for this socket. If further data arrives, reject it.

to be sent. Stop looking for acknowledgement of data already sent; don't retransmit it if it is lost.
 * 1 - Stop trying to transmit data from this socket. Discard any data waiting


 * 2 - Stop both reception and transmission.

The return value is 0 on success and -1 on failure.

int socket (int namespace, int style, int protocol)
This function creates a socket and specifies communication style style, which should be one of the socket styles listed in Communication Styles. The namespace argument specifies the namespace; it must be PF_LOCAL (see Local Namespace) or PF_INET (see Internet Namespace). protocol designates the specific protocol (see Socket Concepts); zero is usually right for protocol.

The return value from socket is the file descriptor for the new socket, or -1 in case of error.

The file descriptor returned by the socket function supports both read and write operations. However, like pipes, sockets do not support file positioning operations.

struct sockaddr
The struct sockaddr type itself has the following members:


 * short int sa_family - This is the code for the address format of this address. It identifies the format of the data which follows.


 * char sa_data[14] - This is the actual socket address data, which is format-dependent. Its length also depends on the format, and may well be more than 14. The length 14 of sa_data is essentially arbitrary.


 * AF_LOCAL - This designates the address format that goes with the local namespace. (PF_LOCAL is the name of that namespace.) See Local Namespace Details, for information about this address format.


 * AF_UNIX - This is a synonym for AF_LOCAL. Although AF_LOCAL is mandated by POSIX.1g, AF_UNIX is portable to more systems. AF_UNIX was the traditional name stemming from BSD, so even most POSIX systems support it. It is also the name of choice in the Unix98 specification. (The same is true for PF_UNIX vs. PF_LOCAL).


 * AF_FILE - This is another synonym for AF_LOCAL, for compatibility. (PF_FILE is likewise a synonym for PF_LOCAL.)


 * AF_INET - This designates the address format that goes with the Internet namespace. (PF_INET is the name of that namespace.) See Internet Address Formats.


 * AF_INET6 - This is similar to AF_INET, but refers to the IPv6 protocol. (PF_INET6 is the name of the corresponding namespace.)


 * AF_UNSPEC This designates no particular address format. It is used only in rare cases, such as to clear out the default destination address of a "connected" datagram socket.

The corresponding namespace designator symbol PF_UNSPEC exists for completeness, but there is no reason to use it in a program.

struct sockaddr_in
This is the data type used to represent socket addresses in the Internet namespace. It has the following members:


 * sa_family_t sin_family - This identifies the address family or format of the socket address. You should store the value AF_INET in this member. See Socket Addresses.


 * struct in_addr sin_addr - This is the Internet address of the host machine. See Host Addresses, and Host Names, for how to get a value to store here.


 * unsigned short int sin_port - This is the port number.

When you call bind or getsockname, you should specify sizeof (struct sockaddr_in) as the length parameter if you are using an IPv4 Internet namespace socket address.

Create the socket
Before to use any socket you have to create it. This can be done via socket function. There is two general types of sockets. A network socket and local socket. TAKE A LOOK ABOUT THE FOLLOWING LINES HOW TO CREATE THE SOCKET.

Network socket
Network socket is used about connecting to a network. Here you are some example how to do that:

int sock; sock = socket ( PF_INET, SOCK_STREAM, IPPROTO_TCP );

The "PF_INET" argument specifies that the socket will be internet socket. Let's take a look about any of the arguments.

PF_INET - specifies the socket type (in our case - internet socket) SOCK_STREAM - specifies that the connection will be via stream. IPPROTO_TCP - the used protocol will be TCP.

In the above example we make a internet socket with TCP packets, simple and easy ...

Local socket
Local socket is used about local connecting. It is used in Interprocess communication Here you are some example how to do that:

int sock; sock = socket ( PF_LOCAL, SOCK_DGRAM, 0 );

The "PF_INET" argument specifies that the socket will be internet socket. Let's take a look about any of the arguments.

PF_LOCAL - specifies the socket type (in our case - local socket) SOCK_DGRAM - specifies that the connection will be via diagrams. 0 - no protocol available.

Initialize the socket structure and make a socket address
After creating of the socket we have to initialize the socket structure to make it available. Well, here is how to do that:

struct sockaddr_in ServAddr; const char * servIP; int ServPort;

memset(&ServAddr, 0, sizeof(ServAddr)); ServAddr.sin_family = AF_INET; ServAddr.sin_addr.s_addr = htonl(INADDR_ANY); ServAddr.sin_port = htons ( port );

This example create internet socket and accepts ALL CONNECTIONS from ANY ADDRESS. Let's have a closer look about the above lines.

This line make memset for ServAddr structure. This structure holds the server address and all information needed about the socket work.

memset(&ServAddr, 0, sizeof(ServAddr));

This line put the socket family. So, as i said above the socket can be internet and local. It this example it is internet, because of that we put AF_INET.

ServAddr.sin_family = AF_INET;

The following line specifies that we accept connections from ANY address.

ServAddr.sin_addr.s_addr = htonl(INADDR_ANY);

s_addr is variable that holds the information about the address we agree to accept. So, in this case i put INADDR_ANY because i would like to accept connections from any internet address. This case is used about server example. In a client example i could NOT accept connections from ANY ADDRESS.

After all above stuffs the next important thing is the PORT. all internet sockets need a Input-Output PORT to make a connection. You can take any port that you want the required condition is that port to be free. So, in other words it must be available for us.

NOTE: Some ports need ROOT rights to opened. If this port is compromised it put entire Operating System on risk.

So, i suggest using a NONE ROOT PORTS that are pretty much available in the computer. These ports start from 1500 - 65536. Well, you have all these ports available for ordinary NONE ROOT users.

Here is the example about the port initializing.

ServAddr.sin_port = htons ( port );

Let me describe the above line. So, the "port" is a "integer variable". You can do it in this way:

ServAddr.sin_port = htons ( 10203 );

This above line will open port 10203 for connections.

Connect to the server
The client can be connected to the server via connect function. That function takes our current socket ( it is a client in that case ) and the server socket and connect them both. Here is the example code:

connect(sock, (struct sockaddr *) &ServAddr, sizeof(ServAddr))

To be everything good and everybody to be happy do the following code:

if (connect(sock, (struct sockaddr *) &ServAddr, sizeof(ServAddr)) < 0) { printf("connect failed\n"); }

This code make sure that we have available connection. If the connection failed then the connect function will return -1 and the logic will print the error message "connect failed". If the function succeeded there is an available and ready for using connection to the server

Binding the socket
After the all preparations the next important step is socket binding. This will bind the socket address and the created socket. So, the address will be connected to the socket. If you miss this stuff you can not use your socket. Because it will have no address to access it. This is like the building and the street number. If you don't know street number you could not find the building you want...

Well, here is the example how to do that:

bind ( sock, ( struct sockaddr * ) &ServAddr, sizeof ( ServAddr ) );

The bind function is very important because it will make your socket available for using. So, better way to do above is to import some processing logic to make sure yourself that is really available socket.

This will do binding of the socket but will check for errors and if the binding failed ... the logic will do exit.

if ( bind ( sock, ( struct sockaddr * ) &ServAddr, sizeof ( ServAddr ) ) < 0 ) { perror ( "bind" ); exit ( EXIT_FAILURE ); }

Listening for incoming connections
listen(sock, MAXPENDING);

The second argument specifies the length of the queue for pending connections. So, if you want to use 5 pending connections you can do it in this way:

listen (sock, 5);

This marks the socket is listening and ready to accept incoming connections.

Accepting connections
The accepting of the connections goes throw some steps... First of all it needs to make a structure with type sockaddr_in to hold client address. After that have to make a variable to hold the client length. Then i put the length of the client to this variable. So, i make sure that there is enough data

Here is the example code:

struct sockaddr_in ClntAddr; unsigned int clntLen;

clntLen = sizeof(ClntAddr); clntSock = accept(servSock, (struct sockaddr *) &ClntAddr, &clntLen))

Sending
When the sockets are connected the next step is just .... using of this connection. :) Sending of data can be established via send or write functions.

Here is the example:

send(sock, "\n", StringLen, 0);

This is simple example how to send a "\n" character to the server. We can send any information. Characters, symbols, any data that have to be sent...

Let me describe the above example... So, the first argument take a socket variable. The second argument take the data that will be sent.. and the 3rd argument is an integer variable that will specify how long is the data sent. The last argument is for additional options, if you don't need that just put 0 - like me. :)

NOTE: The variable "sock" is a socket that will be used. But this is your socket, not the socket of the server... I think this can confuse someone. So, i assume your make a network client and for that reason you make a client socket. That's good but throw this client socket you do all the communications. Have a closer look and see the difference between these 2 sockets. You use the client socket not the server one.. the server socket is for the server.

Just wanted to be clear because some people make mistake when they make a server and client sides.

Receiving
When some data is sent from the other side someone wait to receive it... So, this is not so hard. Here is a simple example:

recv(sock, recvBuffer, 256)

The receiving is like sending - simple and easy. The first argument takes a socket variable, the second variable takes the BUFFER for storing incoming data and the last one takes the integer variable that specifies the length of the incoming data.

So, when you put 256 the read function will read 256 bytes from the incoming data and it will exit when the data is more or find the symbol "END OF DATA".

IMPORTANT: Reserve BUFFER as the same or larger of the length you specify as read data. DO NOT specify buffer that is smaller of the read data. If you do that you will get "SEGMENTATION FAULT" error message and YOUR PROGRAM WILL TERMINATE.

NOTE: The variable "sock" is a socket that will be used. But this is your socket, not the socket of the server... I think this can confuse someone. So, i assume your make a network client and for that reason you make a client socket. That's good but throw this client socket you do all the communications. Have a closer look and see the difference between these 2 sockets. You use the client socket not the server one.. the server socket is for the server.

Just wanted to be clear because some people make mistake when they make a server and client sides.

Advanced tricks
There is a huge amount of advanced tricks in the BSD sockets... This is the main tricks:


 * Receiving data: Data receiving is important part of network socket communications. There is a issue with the buffer when you receive some data via network if you receive data shorter than the length of buffer data. You will receive some $%#$% data... so this is bad. Because of that you have to fix the received buffer and the sent data to be exactly the same length. BUT the receiving buffer must larger +1 character than the sent data. This is because of the last character \0 for terminating the data. So, if you send this : "some data to be send" this is 20 length message. Then buffer for the receiving MUST BE 20 + 1. This is because you send 20 characters, but you receive 20+1 characters. The last one is the terminating character.

network.h

 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 1) include 
 * 2) include 
 * 1) define ADRESS_PORT          10203
 * 2) define ADRESS_IP            "127.0.0.1"
 * 3) define MAXPENDING           5
 * 4) define BUFFSIZE             21
 * 1) define SERVER_SOCKET        1
 * 2) define CLIENT_SOCKET        0
 * 1) define TRUE                 1
 * 2) define FALSE                0
 * 3) define START                11
 * 4) define DIVIDER              ":"

network.c
int make_socket ( uint16_t port, int type, const char * server_IP ) {    int sock; struct hostent *   hostinfo = NULL; struct sockaddr_in server_address; /* Create the socket. */    sock = socket ( PF_INET, SOCK_STREAM, IPPROTO_TCP ); if (sock < 0) { perror ( "socket" ); exit ( 1 ); }    /* Give the socket a name. */    memset(&server_address, 0, sizeof(server_address)); server_address.sin_family = AF_INET; server_address.sin_port = htons ( port ); if ( type == SERVER_SOCKET ) { server_address.sin_addr.s_addr = htonl(INADDR_ANY); if ( bind ( sock, ( struct sockaddr * ) &server_address, sizeof ( server_address ) ) < 0 ) { perror ( "bind" ); exit ( 1 ); }        if ( listen(sock, MAXPENDING) < 0 ) { printf("listen failed"); }    } else if ( type == CLIENT_SOCKET ) { server_address.sin_addr.s_addr = inet_addr(server_IP); /* Establish the connection to the server */ if (connect(sock, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) { printf("connect failed\n"); }    }     return sock; } void close_socket (int socket) {    close (socket); } char * clean_data( const char * data ) {    int count; char * ptr_data     = NULL; char * result_data  = NULL; char * temp_ptr_data = NULL; int len; int write_info, ifone; ptr_data = strstr (data, DIVIDER); ptr_data =& ptr_data[strlen(DIVIDER)]; temp_ptr_data = (char *) malloc ( strlen (ptr_data) ); strcpy (temp_ptr_data, ptr_data); result_data = (char *) strsep (&temp_ptr_data, DIVIDER); printf ("%i, %i, %s", strlen (data), strlen (ptr_data), result_data); return result_data; } void send_data ( int socket, const char * data ) {    int sent_bytes, all_sent_bytes; int err_status; int sendstrlen; sendstrlen = strlen ( data ); all_sent_bytes = 0; sent_bytes = send ( socket, data, sendstrlen, 0 ); all_sent_bytes = all_sent_bytes + sent_bytes; printf ("\t !!! Sent data: %s --- \n", data); }
 * 1) include "network.h"

server.c
int accept_connection(int server_socket) {    int client_socket;                          /* Socket descriptor for client */ struct sockaddr_in client_address;         /* Client address */ unsigned int client_length;                /* Length of client address data structure */ /* Set the size of the in-out parameter */ client_length = sizeof(client_address); /* Wait for a client to connect */ if ((client_socket = accept(server_socket, (struct sockaddr *) &client_address, &client_length)) < 0) { printf("accept failed"); }    /* client_socket is connected to a client! */    printf("Handling client %s\n", inet_ntoa(client_address.sin_addr)); return client_socket; } void handle_client (int client_socket) {    char buffer [BUFFSIZE];           /* Buffer for incomming data */ int msg_size;                    /* Size of received message  */ int bytes, all_bytes; do { alarm (60); msg_size = read (client_socket, buffer, BUFFSIZE); alarm (0); if ( msg_size <= 0 ) { printf ( " %i ", msg_size ); printf ( "End of data\n" ); }    } while ( msg_size > 0 ); printf ("Data received: %s", buffer); bytes = 0; } int main {    int clnt_sock; int sock = make_socket(ADRESS_PORT, SERVER_SOCKET, "none"); clnt_sock = accept_connection (sock); handle_client(clnt_sock); close_socket(sock); }
 * 1) include "network.h"

client.c
int main {    int sock = make_socket(ADRESS_PORT, CLIENT_SOCKET, "10.35.43.41"); send_data (sock, "Some data to be sent"); close_socket(sock); }
 * 1) include "network.h"

How to compile it?
Compile via cc:

cc network.c server.c -o server_example    (server) cc network.c client.c -o client_example    (client)

To compile and use the sockets just have to include the main "include" files. If you don't know which are they ... here you are:

Just import these lines in the beginning of your program .h files.


 * 1) include 
 * 2) include 
 * 3) include 
 * 4) include 
 * 1) include 
 * 2) include 

Include these and should have no problems...

Description
BSD sockets are the base part of the networks and internet. The entire HOW-TO is specified about the BSD socket programming but it could be used by other programmers too. Well, the sockets are the same in all operating systems.

In the general case this HOW-TO will describe about Sockets programming in all
 * NIX-like operating systems. This include Gnu/Linux, *BSD, OpenSolaris and others.

Copyright
Copyright (c) 2006 by Svetoslav P. Chukov. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".