Clever Geek Handbook
📜 ⬆️ ⬇️

Berkeley Sockets

Berkeley Sockets is an application programming interface (API), which is a library for developing C applications with interprocess communication support (IPC), often used in computer networks .

Berkeley sockets (also known as the BSD socket API) first appeared as an API in the 4.1BSD Unix operating system (released in 1982) [1] . However, it was not until 1989 that the University of California at Berkeley was able to begin releasing versions of the operating system and network library without AT & T's licensing restrictions, operating in copyrighted Unix.

The Berkeley Sockets API has actually formed an abstraction standard for network sockets. Most other programming languages ​​use an interface similar to the C language API.

The Transport Level Interface (TLI) API, based on STREAMS, is an alternative to the socket API. However, the Berkeley Sockets API predominantly prevails in popularity and number of implementations.

Berkeley Interface

The Berkeley socket interface is an API that allows you to implement interaction between computers or between processes on the same computer. This technology can work with many different input-output devices and drivers , despite the fact that their support depends on the implementation of the operating system . Such an implementation of the interface underlies TCP / IP , which makes it considered one of the fundamental technologies on which the Internet is based. Socket technology was first developed at UC Berkeley for use on UNIX systems. All modern operating systems have one or another implementation of the Berkeley socket interface, since this has become the standard interface for connecting to the Internet.

Programmers can access the socket interface at three different levels, the most powerful and fundamental of which is the level of raw sockets . A rather small number of applications need to restrict control over outgoing connections implemented by them, so support for raw sockets was intended to be available only on computers used for development based on technologies related to the Internet. Subsequently, most operating systems implemented their support, including Windows XP .

Header Files

The Berkeley Socket Program Library includes many related header files.

<sys/socket.h>
Basic BSD socket functions and data structures.
<netinet/in.h>
The PF_INET and PF_INET6 address / protocol families. Widely used on the Internet, include IP addresses, as well as TCP and UDP port numbers.
<sys/un.h>
Address family PF_UNIX / PF_LOCAL. Used for local interaction between programs running on the same computer. In computer networks does not apply.
<arpa/inet.h>
Functions for working with numeric IP addresses.
<netdb.h>
Functions for converting protocol and host names to numeric addresses. Local data is used in the same way as DNS.

Structures

  • sockaddr is a generalized address structure, to which, depending on the protocol family used, the corresponding structure is given, for example:
  struct sockaddr_in stSockAddr ;
 ...
 bind ( SocketFD , ( const struct sockaddr * ) & stSockAddr , sizeof ( struct sockaddr_in ));
  • sockaddr_in
  • sockaddr_in6
  • in_addr
  • in6_addr

Functions

socket ()

socket() creates the connection endpoint and returns a handle . socket() takes three arguments:

  • domain , indicating the protocol family of the socket to be created. This parameter specifies the naming conventions and address format. For example:
    • PF_INET for IPv4 network protocol or
    • PF_INET6 for IPv6 .
    • PF_UNIX for local sockets (using file).
  • type is one of:
    • SOCK_STREAM reliable thread-oriented service (TCP) (service) or streaming socket
    • SOCK_DGRAM datagram service (UDP) or datagram socket
    • SOCK_SEQPACKET reliable sequential packet service
    • SOCK_RAW Raw socket - raw protocol over the network layer.
  • protocol determines which transport protocol to use. The most common ones are IPPROTO_TCP , IPPROTO_SCTP , IPPROTO_UDP , IPPROTO_DCCP . These protocols are listed in <netinet / in.h>. The value “ 0 ” can be used to select the default protocol from the specified family ( domain ) and type ( type ).

The function returns −1 in case of an error. Otherwise, it returns an integer representing the assigned handle.

Prototype

  #include <sys / types.h> 
 #include <sys / socket.h> 
 int socket ( int domain , int type , int protocol );

gethostbyname () and gethostbyaddr ()

The functions gethostbyname() and gethostbyaddr() return a pointer to an object of type struct hostent , describing an Internet site by name or by address, respectively. This structure contains either information received from the name server or arbitrary fields from the line in / etc / hosts. If the local name server is not running, then these routines scan / etc / hosts. Functions accept the following arguments:

  • name specifying the host name. For example: www.wikipedia.org
  • addr specifies a pointer to a struct in_addr containing the host address.
  • len specifying the length in bytes of addr .
  • type that defines the type of host address area. For example: PF_INET

Functions return a NULL pointer in case of an error. In this case, an additional integer h_errno can be checked to detect an error or an incorrect or unknown host. Otherwise, a valid struct hostent * is returned.

Prototypes

  struct hostent * gethostbyname ( const char * name );
 struct hostent * gethostbyaddr ( const void * addr , int len , int type );

connect ()

connect() Connects to the server. Returns an integer representing the error code: 0 means successful, and −1 indicates an error.

Some types of sockets work without establishing a connection, this mainly applies to UDP sockets. For them, the connection takes on a special meaning: the default target for sending and receiving data is assigned to the transmitted address, allowing you to use functions like send() and recv() on sockets without establishing a connection.

A loaded server may reject a connection attempt, so some types of programs need to provide for repeated connection attempts.

Prototype

  #include <sys / types.h> 
 #include <sys / socket.h> 
 int connect ( int sockfd , const struct sockaddr * serv_addr , socklen_t addrlen );

bind ()

bind() binds a socket to a specific address. When a socket is created using socket() , it is associated with a certain address family, but not with a specific address. Before a socket can accept incoming connections, it must be bound to an address. bind() takes three arguments:

  • sockfd - a descriptor representing the socket when binding
  • serv_addr is a pointer to a sockaddr structure representing the address to which we bind.
  • addrlen is a socklen_t field representing the length of the sockaddr structure.

Returns 0 on success and −1 on error.

Prototype

  #include <sys / types.h> 
 #include <sys / socket.h> 
 int bind ( int sockfd , const struct sockaddr * my_addr , socklen_t addrlen );

listen ()

listen() prepares the binding socket to accept incoming connections (the so-called "listening"). This function is applicable only to the SOCK_STREAM and SOCK_SEQPACKET socket types. Takes two arguments:

  • sockfd is the correct socket descriptor.
  • backlog is an integer indicating the number of established connections that can be processed at any time. The operating system usually sets it equal to the maximum value.

After the connection is accepted, it is removed from the queue. On success, 0 is returned; in the event of an error, −1 is returned.

Prototype

  #include <sys / socket.h> 
 int listen ( int sockfd , int backlog );

accept ()

accept() used to accept a connection request from a remote host. Takes the following arguments:

  • sockfd is the handle of the listening socket to accept the connection.
  • cliaddr - a pointer to the sockaddr structure to accept information about the client's address.
  • addrlen is a pointer to socklen_t , which determines the size of the structure containing the client address and passed to accept() . When accept() returns a value, socklen_t indicates how many bytes of the cliaddr structure are cliaddr use.

The function returns the socket descriptor associated with the accepted connection, or −1 in case of an error.

Prototype

  #include <sys / types.h> 
 #include <sys / socket.h> 
 int accept ( int sockfd , struct sockaddr * cliaddr , socklen_t * addrlen );

Advanced options for sockets

After creating a socket, you can set additional parameters for it. Here are some of them:

  • TCP_NODELAY disables the Nagle algorithm ;
  • SO_KEEPALIVE includes periodic checks for 'signs of life', if supported by the OS.

Blocking and non-blocking sockets

Berkeley sockets can work in one of two modes: blocking or non-blocking. A blocking socket does not return control until it sends (or until it receives) all the data specified for the operation. This is only true for Linux systems. In other systems, such as FreeBSD, it is quite natural for a blocking socket to send not all data (but you can put the MSG_WAITALL flag in send () or recv ()). The application should check the return value to track how many bytes were sent / received and, accordingly, resend the currently unprocessed information [2] . This can lead to problems if the socket continues to “listen”: the program may hang due to the fact that the socket is waiting for data that may never arrive.

A socket is usually indicated as blocking or nonblocking using the fcntl() or ioctl() functions.

Data Transfer

To transfer data, you can use the standard read / write functions of the read and write files, but there are special functions for transmitting data through sockets:

  • send
  • recv
  • sendto
  • recvfrom
  • sendmsg
  • recvmsg

It should be noted that when using the TCP protocol (sockets of the SOCK_STREAM type) there is a chance to receive less data than was transmitted, since not all the data have yet been received, so you need to either wait until the recv function returns 0 bytes, or set the MSG_WAITALL flag function recv , which will make it wait for the transfer to end. For other types of sockets, the MSG_WAITALL flag MSG_WAITALL not change anything (for example, in UDP the entire packet = the whole message). See also the chapter "Blocking and non-blocking sockets."

Releasing Resources

The system does not release the resources allocated by the call to socket() until the call close() occurs. This is especially important if the connect() call failed and can be repeated. Each socket() call must have a corresponding close() call in all possible execution paths. You must add the header file <unistd.h> to support the close function.

The result of the close() system call is only a call to the interface to close the socket, and not close the socket itself. This is the command for the kernel to close the socket. Sometimes on the server side, a socket can go on standby TIME_WAIT for up to 4 minutes. [one]

Sample client and server using TCP

TCP implements the concept of a connection. The process creates a TCP socket by calling the socket() function with the PF_INET or PF_INET6 , as well as SOCK_STREAM (Stream Socket) and IPPROTO_TCP .

Server

Creating a simple TCP server consists of the following steps:

  • Creating TCP sockets by calling the socket() function.
  • Binding a socket to a listening port by calling the bind() function. Before calling bind() programmer must declare a sockaddr_in structure, clear it (using memset() ), then sin_family ( PF_INET or PF_INET6 ) and fill in the sin_port fields (listened port, specified as a sequence of bytes ). The conversion of short int to byte order can be performed by calling the htons() function (short for “from host to network”).
  • Preparing a socket for listening for connections (creating a listening socket) by calling listen() .
  • accept() incoming connections via accept() . This blocks the socket until an incoming connection is received, and then returns a socket descriptor for the accepted connection. The initial descriptor remains a descriptor listened, and accept() can be called again for this socket at any time (as long as it is open).
  • A connection to a remote host that can be created using send() and recv() or write() and read() .
  • The final closure of each open socket that is no longer needed occurs with close() . It should be noted that if there were any fork() calls, then each process should close its known sockets (the kernel keeps track of the number of processes that have an open handle), and in addition, two processes should not use the same socket at the same time.
  / * C server code * /

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

 #define port 1100

 int main ( void ) {
	 struct sockaddr_in stSockAddr ;
	 int i32SocketFD = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP );

	 if ( i32SocketFD == - 1 ) {
		 perror ( "error creating socket" );
		 exit ( EXIT_FAILURE );
	 }

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

	 stSockAddr .  sin_family = PF_INET ;
	 stSockAddr .  sin_port = htons ( port );
	 stSockAddr .  sin_addr .  s_addr = htonl ( INADDR_ANY );

	 if ( bind ( i32SocketFD , ( struct sockaddr * ) & stSockAddr , sizeof ( stSockAddr )) == - 1 ) {
		 perror ( "Error: bind" );

		 close ( i32SocketFD );
		 exit ( EXIT_FAILURE );
	 }

	 if ( listen ( i32SocketFD , 10 ) == - 1 ) {
		 perror ( "Error: Listening" );

		 close ( i32SocketFD );
		 exit ( EXIT_FAILURE );
	 }

	 for (;;) {
		 int i32ConnectFD = accept ( i32SocketFD , 0 , 0 );

		 if ( i32ConnectFD < 0 ) {
			 perror ( "Error: Accept " );
			 close ( i32SocketFD );
			 exit ( EXIT_FAILURE );
		 }

		 / * read and write operations ... * /

		 shutdown ( i32ConnectFD , SHUT_RDWR );

		 close ( i32ConnectFD );
	 }

	 return 0 ;
 }

Customer

Creating a TCP client is as follows:

  • Creating a TCP socket by calling socket() .
  • Connect to the server using connect() , passing the sockaddr_in structure with sin_family with the specified PF_INET or PF_INET6 , sin_port to specify the listening port (in byte order), and sin_addr to specify the IPv4 or IPv6 address of the server being listened to (also in byte order).
  • Interaction with the server using send() and recv() or write() and read() .
  • End a connection and reset information when you call close() . Similarly, if there were any fork() calls, each process must close the ( close() ) socket.
  / * Client code in C * /

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

 int main ( void ) {
	 struct sockaddr_in stSockAddr ;
	 int i32Res ;
	 int i32SocketFD = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP );

	 if ( i32SocketFD == - 1 ) {
		 perror ( "Error: unable to create socket" );
		 return EXIT_FAILURE ;
	 }

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

	 stSockAddr .  sin_family = PF_INET ;
	 stSockAddr .  sin_port = htons ( 1100 );
	 i32Res = inet_pton ( PF_INET , "192.168.1.3" , & stSockAddr . sin_addr );

	 if ( i32Res < 0 ) {
		 perror ( "Error: the first parameter does not belong to the category of valid addresses" );
		 close ( i32SocketFD );
		 return EXIT_FAILURE ;
	 } else if ( ! i32Res ) {
		 perror ( "Error: the second parameter does not contain a valid IP address" );
		 close ( i32SocketFD );
		 return EXIT_FAILURE ;
	 }

	 if ( connect ( i32SocketFD , ( struct sockaddr * ) & stSockAddr , sizeof ( stSockAddr )) == - 1 ) {
		 perror ( "Error: Connections" );
		 close ( i32SocketFD );
		 return EXIT_FAILURE ;
	 }

	 / * read and write operations ... * /

	 shutdown ( i32SocketFD , SHUT_RDWR );

	 close ( i32SocketFD );
	 return 0 ;
 }

Sample client and server using UDP

UDP is based on a connectionless protocol, that is, a protocol that does not guarantee the delivery of information. UDP packets may not arrive in the specified order, be duplicated and arrive more than once, or even not reach the addressee at all. Because of these minimal guarantees, UDP is significantly inferior to TCP. The absence of a connection means the absence of streams or connections between two hosts, since instead data arrives in datagrams ( datagram socket ).

UDP address space, the area of ​​UDP port numbers (in ISO terminology - TSAP) is completely separated from TCP ports.

Server

The code can create a UDP server on port 7654 as follows:

  int sock = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP );

 struct sockaddr_in sa ;
 int bound ;
 ssize_t recsize ;
 socklen_t * address_len = NULL ;

 sa .  sin_addr .  s_addr = htonl ( INADDR_ANY );
 sa .  sin_port = htons ( 7654 );

 bound = bind ( sock , ( struct sockaddr * ) & sa , sizeof ( struct sockaddr ) );

 if ( bound < 0 )
   fprintf ( stderr , "bind (): error% s \ n " , strerror ( errno ) );

bind () binds a socket to an address / port pair.

  while ( 1 )
   {
     printf ( "recv test .... \ n " );
     recsize = recvfrom ( sock , ( void * ) Hz , 100 , 0 , ( struct sockaddr * ) & sa , address_len );

     if ( recsize < 0 )
       fprintf ( stderr , "Error% s \ n " , strerror ( errno ) );

     printf ( "recsize:% d \ n " , recsize );
     sleep ( 1 );
     printf ( "datagram:% s \ n " , Hz );
   }

Such an infinite loop receives all UDP datagrams arriving on port 7654 using recvfrom () . The function uses the parameters:

  • socket
  • pointer to data buffer
  • buffer size
  • flags (similar to reading or other socket receive functions),
  • sender address structure
  • The length of the sender's address structure.

Customer

The simplest demonstration of sending a UDP packet containing “Hello!” To the address 127.0.0.1, port 7654, looks like this:

  #include <stdio.h> 
 #include <errno.h> 
 #include <string.h> 
 #include <sys / socket.h> 
 #include <sys / types.h> 
 #include <netinet / in.h> 
 #include <unistd.h> / * to call close () for a socket * / 

 int main ( void )
   {
     int sock ;
     struct sockaddr_in sa ;
     int bytes_sent ;
     const char * buffer = "Hello!"  ;
     int buffer_length ;

     buffer_length = strlen ( buffer ) + 1 ;

     sock = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP );

     if ( sock == - 1 )
       {
          printf ( "Error creating socket" );
          return 0 ;
       }

     sa .  sin_family = PF_INET ;
     sa .  sin_addr .  s_addr = htonl ( 0x7F000001 );
     sa .  sin_port = htons ( 7654 );

     bytes_sent =
       sendto (
         sock
         buffer ,
         strlen ( buffer ) + 1 ,
         0 ,
         ( struct sockaddr * ) & sa ,
         sizeof ( struct sockaddr_in )
       );

     if ( bytes_sent < 0 )
       printf ( "Error sending package:% s \ n " , strerror ( errno ) );

     close ( sock );
     return 0 ;
   }

See also

  • Computer network
  • Internet socket
  • UNIX domain socket
  • Winsock is an API based on Berkeley sockets, but intended to create distributed applications on the Microsoft Windows platform .

Notes

  1. ↑ Uresh Vahalia. UNIX internals: the new frontiers. - Upper Saddle River, New Jersey 07458: Prentice Hall PTR, 2003. - 844 p. - ISBN 0-13-101908-2 .
  2. ↑ Beej's Guide to Network Programming

Links

The de jure definition of the sockets interface is contained in the POSIX standard, better known as:

  • IEEE Std. 1003.1-2001 Standard for Information Technology - Portable Operating System Interface (POSIX).
  • Open Group Technical Standard: Base Specifications, Issue 6, December 2001.
  • ISO / IEC 9945: 2002
  • Austin's website - information about these standards, as well as current work on them.
  • RFC3493 and RFC3542 describe the IPv6 extension of the underlying socket API.
  • Unix Manual Pages
    • accept (2)
    • connect (2)
  • "Learn the algorithms of TCP system calls" (rus.) On the IBM website.
  • Kaspersky K. "Tutorial games for WINSOCK"
  • Beej's Guide to Network Programming - 2007
  • UnixSocket FAQ
  • Get system IP list - C ++ Example
  • quick TCP-IP NetIntro with C examples
  • Porting Berkeley Socket programs to Winsock - Microsoft's documentation.
  • Programming UNIX Sockets in C - Frequently Asked Questions - 1996
  • Linux network programming - Linux Journal , 1998
Source - https://ru.wikipedia.org/w/index.php?title=Sokety_Berkli&oldid=101001550


More articles:

  • Malkin, Evgeny Vladimirovich
  • June 2 Motion
  • The Pogues
  • Klose, Friedrich
  • Muhammad Ali (artist, worked in Isfahan)
  • Montenegro at Eurovision 2009
  • Emilio Vedova
  • Mauritania Tingitanskaya
  • David Sarser
  • Gijak

All articles

Clever Geek | 2019