Socket (software)
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 :
- Create socket
- Connect the socket created with the server address from which data is to be requested
- Sending and receiving data
- possibly shut down socket (
shutdown()
,close()
) - Disconnect, close socket
Server-side :
- Create server socket
- Binding the socket to an address (port) via which requests are accepted
- waiting for inquiries
- Accept the request and thus create a new socket pair for this client
- Processing of the client request on the new client socket
- Close the client socket again.
Datagram sockets
Client side :
- Create socket
- Send to address
Server-side :
- Create socket
- Bind socket
- 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()
andrecv()
, orwrite()
andread()
, orsendto()
andrecvfrom()
Writes / reads data to / from socket (s). Note: A one-time function call fromrecv()
does not guarantee the reception of allsend()
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 Socket
and 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 Network
a 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 socket
also 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
- UNIX Programmer's Supplementary Documents (PSD: 20-1) (PDF; English)
- Socket Programming in Python (english)
- Realistic example of the construction of a socket server with secure termination in Haskell
- Guide to Network Programming Using Internet Sockets (PDF; 720 kB; English)
- Sockets . GNU info page (English)
Individual evidence
- ^ Concurrency demos / Graceful exit on wiki.haskell.org