Socket (software)

from Wikipedia, the free encyclopedia

A socket (from Engl. Socket , plug or socket ) is from operating system -provided object that serves as a communication endpoint. A program uses sockets to exchange data with other programs. The other program can be on the same computer ( interprocess communication ) or on another computer that can be accessed via the network . Communication via sockets is usually bidirectional , which means that data can both be received and sent via the socket.

functionality

General functional principle

Sockets are a platform-independent, standardized interface ( API ) between the network protocol - implementation of the operating system and the actual application software . A computer program requests a socket from the operating system. The operating system has the task of managing all used sockets and the associated connection information.

Internet sockets

Internet sockets enable communication using certain communication protocols . Generally, one can distinguish between stream sockets and datagram sockets : stream sockets communicate via a character - stream ; Datagram sockets over individual messages. In network communication, stream sockets mostly use TCP , datagram sockets usually use UDP . TCP is more reliable, the sequence and delivery of packets are guaranteed (principle: all or nothing). UDP is more efficient and flexible for certain tasks, often faster (in terms of time) - however, the sequence and delivery of the packets are not guaranteed (duplicates are still possible).

While stream sockets and datagram sockets the TCP or UDP header of a data packet usually hide and set automatically let raw sockets ( Raw : Raw) to create their own TCP and UDP headers to. Raw sockets are most likely used in network-related applications, e.g. B. for routers , packet sniffers or packet injection .

A socket is usually the connection point to a specific remote program, represented by its address information (e.g. IP address and port number). The socket itself is of course also assigned its own address information. An Internet socket address of the AF_INET family is represented by the following information:

  • sin_family, i.e. the associated address family of the network (e.g. AF_INET = address family Internet address)
  • the identification number of the localhost / its 32-bit IP address
  • the port number of the localhost / 16 bit

However, this information depends on the protocol used . Typically, the address information on the Internet is the IP address and the port . With UNIX domain sockets ( see below ) the identification consists of a file path name and the address family AF_UNIX.

A server can either wait for requests from a specific address (and binds itself to this address from the start) or it waits for requests on all addresses on its computer. Some protocols have a so-called wildcard address for which one or more parts of the address information are not specific. In the example of TCP / IP and UDP / IP, only the port number is relevant for a wildcard address, i.e. a special (invalid) IP address is specified to indicate that connections are accepted on all IP addresses should be. Under Linux this wildcard address is 0.0.0.0 (symbolic constant INADDR_ANY).

When the server receives a request from a client, the "connected" server socket is derived from the listening server socket: The original server socket is retained and continues to wait for new connections. while a new socket directed to the specific client is opened, which is only used for communication with this one client. This remains in place until the connection to the client is terminated from either side. This derivation can be used to create a parallelized server architecture in which the server forks itself on a request and a child process answers the request itself.

This means that a “connected” server socket connected to a client socket has exactly the same IP address and port number as the listening (“listen”) server socket. The distinction between simultaneous client connections to the same server is therefore made by the pair of server socket and client socket. This pair must be unique to each of the communication partners involved at all times. As an example, consider an HTTP server that listens on port 80. The connections of the server to different clients lead to the following unique "Connected" socket pairs on the server computer:

(<Server-IP>: 80; <Client_A-IP>: <Client_A_Port_1>), (<Server-IP>: 80; <Client_A-IP>: <Client_A_Port_2>), (<Server-IP>: 80; < Client_B-IP>: <Client_B_Port_1>) etc.

Socket communication sequence

Stream Sockets

Client side :

  1. Create socket
  2. Connect the socket created with the server address from which data is to be requested
  3. Sending and receiving data
  4. possibly shut down socket ( shutdown(), close())
  5. Disconnect, close socket

Server-side :

  1. Create server socket
  2. Binding the socket to an address (port) via which requests are accepted
  3. waiting for inquiries
  4. Accept the request and thus create a new socket pair for this client
  5. Processing of the client request on the new client socket
  6. Close the client socket again.

Datagram sockets

Client side :

  1. Create socket
  2. Send to address

Server-side :

  1. Create socket
  2. Bind socket
  3. waiting for packages

Sockets and interprocess communication

Unix operating systems use for local interprocess communication called POSIX Local Inter-Process Communication sockets (also IPC sockets , of "inter-process communication sockets", or Unix domain sockets ). Here, too, there are datagram and stream sockets; However, since communication takes place in the kernel, stream and datagram sockets behave very similarly (e.g. there is no risk of data loss with datagram sockets either). A Unix domain socket is represented as a special file in the file system. Instead of the IP address and port number, the full path of the socket serves as a unique identification (e.g. /var/run/snmpd.sock). Unix domain sockets have the advantage of a much higher throughput for the IPC compared to connections that use the loopback interface.

Alternatives to sockets in interprocess communication are pipes or shared memory .

history

A central design principle of Unix is: Everything is a file. The four most commonly used system calls for working with files are: open()open, read()read, write()write, and close()close. Sockets represent the implementation of this design principle.

The Socket API was originally developed in 1983 for BSD Unix . The specification was later incorporated into the POSIX standard . It is now available on every POSIX-compliant operating system. Other operating systems such as Microsoft Windows ( Winsock ) or OS / 2 have also adopted the socket API. The general spread of sockets is due not only to the design of sockets, but also to the general availability of the source code thanks to the BSD license.

Use in different operating systems

Unix and Unix -like operating systems (such as Linux ) very often use BSD sockets for network communication. For local interprocess communication , they use the Unix domain sockets described above (which are part of the POSIX standard) and with which processes can communicate with one another in a simple manner. After the socket has been initialized, the programmer can work with it like a file.

Windows uses a so-called Windows Sockets API (Winsock) that is based on BSD sockets .

Socket programming

BSD Sockets API

Both Unix Sockets and Windows Sockets are based on the BSD Sockets API published in 1983. Important functions of this API are briefly summarized here for the following programming examples:

  • socket()Creates a new socket of a certain type and allocates system resources for it. The function returns a unique integer type number for identification.
  • bind()Binds the socket to socket address information, usually an IP address and port. Typically used on the server side.
  • listen()Puts a bound STREAM (TCP / IP) socket into listening mode. Is used on the server side.
  • connect()Announces the address information (e.g. IP address and port) of another socket. Assigns a free local port to the socket. In the case of a STREAM socket, an attempt is made to establish a new TCP / IP connection. Is used on the client side.
  • accept()Accepts an incoming attempt (request) to set up a new TCP / IP connection to a remote client and, if successful, creates a new socket associated with the address pair of the connection. This newly created socket is returned by the function. Is used on the server side.
  • send()and recv(), or write()and read(), or sendto()and recvfrom()Writes / reads data to / from socket (s). Note: A one-time function call from recv()does not guarantee the reception of all send()data sent by the sender , especially not with STREAM sockets.
  • close()Causes the operating system to release all resources allocated for the socket. If there is a TCP / IP socket, the connection is terminated.

C.

The Linux derived POSIX Sockets API is written in C. An example of a TCP connection establishment from a client to a server:

int sockfd = socket(AF_INET, SOCK_STREAM, 0); // Erzeuge Socket

struct sockaddr_in srv;

memset(&srv, 0, sizeof(struct sockaddr_in));

srv.sin_family = AF_INET;
inet_pton(AF_INET, "1.2.3.4", &srv.sin_addr); // Schreibe IP-Adresse des Servers in die sockaddr_in-Struktur
srv.sin_port = htons(1234); // Schreibe Port in Network-Byte-Order (Big Endian) in das Feld sin_port

connect(sockfd, (struct sockaddr*)&srv, sizeof(struct sockaddr_in)); // Verbindung herstellen

// Ab jetzt kann mit write() und read() aus dem Socket gelesen und in das Socket geschrieben werden.

[...] // Datenaustausch

shutdown(sockfd, SHUT_WR); // Sende ein EOF-Byte, sodass der Server beim nächsten read() als Rückgabewert 0 bekommt
                           //und die Verbindung beenden kann

close(sockfd);

C #

// set IP adress and port for remote host
IPAddress ipAddress = IPAddress.Parse("192.168.xxx.yyy");
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 9999);
Socket sock = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// open socket
sock.Connect(ipEndPoint);
// check if socket is connected
if (sock.Connected)
{
	// endless loop
	while(true)
	{
		// set receive buffer and length, is buffer big enough?
		byte[] bytesReceived = new byte[1024];
        int bytes = 0;
        // send message 
		byte[] msg1 = new byte[256];
		// ... set your bytes, ASCII or whatever
        sock.Send(msg1, msg1.Length, SocketFlags.None);
		// receive message
        bytes = sock.Receive(bytesReceived, bytesReceived.Length, SocketFlags.None);
	}
	sock.Shutdown(SocketShutdown.Both);
    sock.Close();
}

Java

Java as a platform-independent programming languagejava.net directly supports socket programming in the package . This shows that the socket concept is independent of the operating system. The implementation of the sockets for the various platforms (Linux, Windows, special systems) takes place in the class library of the virtual machine .

The classes for socket programming are Socketand ServerSocket. The following short example shows the usage:

 ServerSocket serverSocket = new ServerSocket(port);    //Serversocket mit bestimmter Port-Nummer erstellen
 while(true)
 {
   Socket clientSocket = serverSocket.accept();         //auf Anfragen warten
   InputStream input   = clientSocket.getInputStream(); //InputStream-Objekt öffnen
   byte[] data         = new byte[1024];                //Datenpuffer deklarieren (anlegen)
   int numBytes        = 0;                             //Variable für Anzahl der tatsächlich gelesenen Bytes
   numBytes            = input.read(data);              //Daten lesen
   /*** gelesene Daten verarbeiten ***/
   clientSocket.close();                                //Verbindung schließen
 }

The current Java version also offers the option of addressing sockets via the NewIO (nio) library. The code is a bit more involved, but it can be executed faster. Multiple sockets are multiplexed using a so-called selector (comparable to the Unix system call select ).

Haskell

The purely functional programming language Haskell offers Networka platform-independent possibility to use sockets through the module . The following example contains the complete code for a very simple server and a corresponding client . The client accepts lines of text from the standard input and sends them to the server via the network socket. This in turn outputs the text lines on the standard output.

The server shown here is simple in that it z. B. is unlikely to allow safe termination. One possible solution is shown in haskell.org using Software Transactional Memory (STM) .

Simple server

module Main where

import Control.Concurrent
import Control.Monad
import System.IO
import Network

main :: IO ()
main = withSocketsDo $ do
         theSocket <- listenOn (PortNumber 2048)
         forever $ acceptConnectionAndFork theSocket echoServer

type MessageHandler = (Handle, String, PortNumber) -> IO ()

acceptConnectionAndFork :: Socket -> MessageHandler -> IO ()
acceptConnectionAndFork theSocket handler = do
  connection <- accept theSocket
  forkIO $ handler connection
  return ()

echoServer :: MessageHandler
echoServer (handle,hostname,portnumber) = do
  putStrLn $ "("++hostname++":"++show portnumber++"): Open"
  c <- hGetContents handle
  mapM_ putStrLn ["("++hostname++":"++show portnumber++"): Msg "++show l | l<-lines c]
  putStrLn $ "("++hostname++":"++show portnumber++"): Close"

Simple client

module Main where

import Network
import System.IO
import Control.Concurrent

main :: IO ()
main = withSocketsDo $ do
         handle <- connectTo "localhost" (PortNumber 2048)
         input <- getContents
         sequence_ [do
                      hPutStrLn handle l
                      hFlush handle |
                   l<-lines input]
         hClose handle

Ruby

In Ruby, the standard library socketalso provides a platform-independent interface for programming TCP sockets.

A very simple server (with multithreading) that sends a text to the client:

require 'socket'

port = 2048
server = TCPServer.new(port)
loop do
  client = server.accept
  Thread.start(client) do |c|
    c.puts 'Hello!'
    c.close
  end
end

Python 3

A simple program that sends messages to the server via the client.

server

import socket

# Server

host = "127.0.0.1"      # IP adress of the Server
port = 5000             # Port used by the server
    
s = socket.socket()
s.bind((host, port))
s.listen(1)

while True:

    client, addr = s.accept()
    print(f"Connected to {addr}")

    while True:
        
        data = client.recv(1024)
        if not data:
            break
        
        print(f"Received from client: {data.decode()}")

        client.sendall(data)

Client

import socket


host = "127.0.0.1"      # IP adress of the Server
port = 5000             # Port used by server

s = socket.socket()     
s.connect((host, port))

while True:
    msg = str(input("Message -> "))

    s.sendall(msg.encode())
    
    data = s.recv(1024)
    print(f"Received from server: {data.decode()}")

Node.js

In Node.js, the standard module "net" enables the programming of TCP sockets.

var net = require('net');

var server = net.createServer(function (socket) {
  socket.write('Echo server\r\n');
  socket.pipe(socket);
});

server.listen(1337, '127.0.0.1');

Web links

Individual evidence

  1. ^ Concurrency demos / Graceful exit on wiki.haskell.org