Socket-Programmierung: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
Zeile 235: | Zeile 235: | ||
==== Links ==== | ==== Links ==== | ||
===== Weblinks ===== | ===== Weblinks ===== | ||
# https://de.wikipedia.org/wiki/Socket_(Software) | |||
</noinclude> | </noinclude> |
Version vom 18. November 2023, 20:58 Uhr
topic - Kurzbeschreibung
Beschreibung
BSD Sockets API
Sowohl Unix Sockets als auch Windows Sockets basieren auf der 1983 veröffentlichten BSD Sockets API. Für die nachfolgenden Programmierbeispiele sind wichtige Funktionen dieser API hier kurz zusammengefasst:
socket()
Erzeugt ein neues Socket bestimmten Types und alloziert hierfür Systemressourcen. Für die Identifizierung gibt die Funktion eine eindeutige Zahl vom Typ Integer zurück.bind()
Bindet den Socket an eine Socket Adressinformation, in der Regel an eine IP-Adresse und Port. Wird typischerweise auf Server-Seite benutzt.listen()
Versetzt einen gebundenen STREAM (TCP/IP) Socket in einen Lauschen-Modus. Wird auf Server-Seite benutzt.connect()
Macht die Adressinformation (z. B. IP-Adresse und Port) eines anderen Sockets bekannt. Ordnet dem Socket einen freien lokalen Port zu. Im Falle eines STREAM Sockets wird versucht eine neue TCP/IP-Verbindung zu etablieren. Wird auf Client-Seite benutzt.accept()
Akzeptiert einen eingehenden Versuch (Anfrage), eine neue TCP/IP-Verbindung zu einem entfernten Client aufzubauen, und erzeugt im Erfolgsfall ein neues Socket, assoziiert mit dem Adress-Paar der Verbindung. Dieses neu erzeugte Socket wird von der Funktion zurückgegeben. Wird auf Server-Seite benutzt.send()
undrecv()
, oderwrite()
undread()
, odersendto()
undrecvfrom()
Schreibt / liest Daten an / von Socket(s). Hinweis: Ein einmaliger Funktionsaufruf vonrecv()
garantiert nicht den Empfang aller vom Sender mittelssend()
gesendeten Daten, insbesondere nicht bei STREAM Sockets.close()
Veranlasst das Betriebssystem alle für das Socket allozierten Ressourcen freizugeben. Liegt ein TCP/IP Socket vor, wird die Verbindung beendet.
C
Die abgeleitete POSIX-Sockets-API von Linux ist in C geschrieben. Ein Beispiel für einen TCP-Verbindungsaufbau eines Clients zu einem 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 als plattformunabhängige Programmiersprache unterstützt im Paket java.net
unmittelbar die Socket-Programmierung. Das zeigt die Betriebssystemunabhängigkeit des Socket-Konzeptes. Die Implementierung der Sockets für die verschiedenen Plattformen (Linux, Windows, Spezialsysteme) erfolgt in der Klassenbibliothek der virtuellen Maschine.
Die Klassen für die Socket-Programmierung sind Socket
und ServerSocket
. Folgendes Kurzbeispiel zeigt die Verwendung:
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
}
Weiterhin gibt es in der aktuellen Java-Version die Möglichkeit, Sockets über die NewIO-(nio)-Bibliothek anzusprechen. Der Code ist etwas aufwändiger, kann jedoch schneller ausgeführt werden. Das Multiplexing mehrerer Sockets geschieht über einen so genannten Selector (vergleichbar dem Unix-Systemaufruf select).
Haskell
Die rein funktionale Programmiersprache Haskell bietet durch das Modul Network
eine plattformunabhängige Möglichkeit zur Verwendung von Sockets. Das folgende Beispiel beinhaltet den vollständigen Code für einen sehr einfachen Server und einen korrespondierenden Client. Der Client nimmt Textzeilen von der Standardeingabe entgegen und schickt diese über den Netzwerk-Socket an den Server. Dieser wiederum gibt die Textzeilen auf die Standardausgabe aus.
Der hier gezeigte Server ist insofern einfach, als er z. B. eine sichere Beendigung wahrscheinlich nicht ermöglicht. Eine Lösungsmöglichkeit wird in haskell.org[1] unter Verwendung von Software Transactional Memory (STM) aufgezeigt.
Einfacher 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"
Einfacher 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 stellt die Standardbibliothek socket
ebenfalls plattformunabhängig eine Schnittstelle zur Programmierung von TCP-Sockets zur Verfügung.
Ein sehr einfacher Server (mit Multithreading), der einen Text an den Client schickt:
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
Ein einfaches Programm, das über den Client Nachrichten an den Server schickt.
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 ermöglicht das Standardmodul "net" die Programmierung von 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');
Anhang
Siehe auch
Links
Weblinks
- ↑ Concurrency demos/Graceful exit auf wiki.haskell.org