====== std.net.socket ====== Umfassende Socket-Abstraktion für TCP, UDP, Unix Domain Sockets und Raw Sockets. Ermöglicht den Aufbau von Client- und Serveranwendungen auf Netzwerkebene – von einfachen Verbindungen bis hin zu nicht-blockierendem I/O mit Poll/Select-Multiplexing. Enthält außerdem Low-Level-Funktionen für ICMP-Ping, ARP-Paketgenerierung und Ethernet-Header-Erstellung. Diese Unit bildet die Grundlage für alle höheren Netzwerkprotokolle in der Lyx-Standardbibliothek (HTTP, DNS, SMTP etc.). import std.net.socket; var listener: TCPListener := TCPListenerNew(); TCPListenerBind(listener, 8080); TCPListenerListen(listener, 16); // Backlog: wartende Verbindungen var conn: TCPConn := TCPListenerAccept(listener); TCPConnWrite(conn, "Hello\n", 6); TCPConnClose(conn); ---- ===== Imports ===== * ''std.net.types'' * ''std.net.syscalls'' ---- ===== Funktionen ===== ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''BufferAlloc(size: int64): int64'' | pub | Alloziert Speicherpuffer der Größe n | | ''BufferFree(buf: int64, size: int64): int64'' | pub | Gibt Speicherpuffer frei | ---- ===== Typen ===== ==== TCPListener (struct) ==== ^ Feld ^ Typ ^ | ''fd'' | ''int64'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''TCPListenerNew(): TCPListener'' | pub | Erstellt neuen TCP-Listener-Socket | | ''TCPListenerSetReuseAddr(listener: TCPListener): int64'' | pub | Aktiviert SO_REUSEADDR am Listener | | ''TCPListenerSetReusePort(listener: TCPListener): int64'' | pub | Aktiviert SO_REUSEPORT am Listener | | ''TCPListenerSetBacklog(listener: TCPListener, backlog: int64): int64'' | pub | Setzt maximale Warteschlangenlänge | | ''TCPListenerBind(listener: TCPListener, addr: int64): int64'' | pub | Bindet Listener an Adressstruktur | | ''TCPListenerBindTo(listener: TCPListener, ip: int64, port: int64): int64'' | pub | Bindet Listener an IP und Port | | ''TCPListenerListen(listener: TCPListener, backlog: int64): int64'' | pub | Startet Verbindungsannahme | | ''TCPListenerAccept(listener: TCPListener): TCPConn'' | pub | Nimmt eingehende TCP-Verbindung an | | ''TCPListenerClose(listener: TCPListener)'' | pub | Schließt Listener-Socket | ==== TCPConn (struct) ==== ^ Feld ^ Typ ^ | ''fd'' | ''int64'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''TCPConnRead(conn: TCPConn, buf: int64, n: int64): int64'' | pub | Liest Bytes aus TCP-Verbindung | | ''TCPConnWrite(conn: TCPConn, buf: int64, n: int64): int64'' | pub | Schreibt Bytes in TCP-Verbindung | | ''TCPConnClose(conn: TCPConn)'' | pub | Schließt TCP-Verbindung | | ''TCPConnSetNodelay(conn: TCPConn, enable: bool): int64'' | pub | Aktiviert oder deaktiviert TCP_NODELAY | | ''TCPConnSetKeepAlive(conn: TCPConn, enable: bool): int64'' | pub | Aktiviert oder deaktiviert Keep-Alive | | ''TCPConnGetError(conn: TCPConn): int64'' | pub | Liest Fehlercode der Verbindung | | ''TCPConnSetRecvBuf(conn: TCPConn, size: int64): int64'' | pub | Setzt Empfangspuffergröße | | ''TCPConnSetSendBuf(conn: TCPConn, size: int64): int64'' | pub | Setzt Sendepuffergröße | | ''TCPConnSetReuseAddr(conn: TCPConn, enable: bool): int64'' | pub | Aktiviert SO_REUSEADDR an Verbindung | | ''TCPConnect(ip: int64, port: int64): TCPConn'' | pub | Stellt TCP-Verbindung zu IP:Port her | | ''TCPConnectAddr(ipAddr: IPAddr): TCPConn'' | pub | Stellt TCP-Verbindung via IPAddr her | ==== UDPSocket (struct) ==== ^ Feld ^ Typ ^ | ''fd'' | ''int64'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''UDPSocketNew(): UDPSocket'' | pub | Erstellt neuen UDP-Socket | | ''UDPSocketBind(sock: UDPSocket, addr: int64): int64'' | pub | Bindet UDP-Socket an Adressstruktur | | ''UDPSocketBindTo(sock: UDPSocket, ip: int64, port: int64): int64'' | pub | Bindet UDP-Socket an IP und Port | | ''UDPSocketSendTo(sock: UDPSocket, buf: int64, n: int64, dest: int64): int64'' | pub | Sendet Datagramm an Zieladresse | | ''UDPSocketSendToAddr(sock: UDPSocket, buf: int64, n: int64, ip: int64, port: int64): int64'' | pub | Sendet Datagramm an IP:Port | | ''UDPSocketRecvFrom(sock: UDPSocket, buf: int64, n: int64, src: int64, addrlen: int64): int64'' | pub | Empfängt Datagramm mit Absenderadresse | | ''UDPSocketRecv(sock: UDPSocket, buf: int64, n: int64, senderIP: int64, senderPort: int64): int64'' | pub | Empfängt Datagramm mit IP und Port | | ''UDPSocketClose(sock: UDPSocket)'' | pub | Schließt UDP-Socket | | ''UDPSocketSetReuseAddr(sock: UDPSocket): int64'' | pub | Aktiviert SO_REUSEADDR am UDP-Socket | | ''UDPSocketSetBroadcast(sock: UDPSocket, an: bool): int64'' | pub | Aktiviert SO_BROADCAST — ohne diese Option weist der Kernel jeden Versand an eine Rundrufadresse mit ''EACCES'' ab | | ''UDPSocketSetRecvBuf(sock: UDPSocket, size: int64): int64'' | pub | Setzt Empfangspuffergröße | | ''UDPSocketSetSendBuf(sock: UDPSocket, size: int64): int64'' | pub | Setzt Sendepuffergröße | | ''UDPSocketGetError(sock: UDPSocket): int64'' | pub | Liest Fehlercode des UDP-Sockets | ==== RawSocket (struct) ==== ^ Feld ^ Typ ^ | ''fd'' | ''int64'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''RawSocketNew(protocol: int64): RawSocket'' | pub | Erstellt Raw-Socket für Protokoll | | ''RawSocketSendTo(sock: RawSocket, buf: int64, n: int64, destAddr: int64): int64'' | pub | Sendet Rohpaket an Zieladresse | | ''RawSocketRecvFrom(sock: RawSocket, buf: int64, n: int64, srcAddr: int64, addrlen: int64): int64'' | pub | Empfängt Rohpaket mit Quelladresse | | ''RawSocketClose(sock: RawSocket)'' | pub | Schließt Raw-Socket | ==== ICMPHeader (struct) ==== ^ Feld ^ Typ ^ | ''icmp_type'' | ''uint8'' | | ''icmp_code'' | ''uint8'' | | ''icmp_cksum'' | ''uint16'' | | ''icmp_id'' | ''uint16'' | | ''icmp_seq'' | ''uint16'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''ICMPMakeEchoRequest(id: int64, seq: int64): ICMPHeader'' | pub | Erstellt ICMP-Echo-Request-Header | | ''ICMPChecksum(data: int64, len: int64): int64'' | pub | Berechnet ICMP-Prüfsumme | | ''ICMPPing(destIP: int64, id: int64, seq: int64, timeoutSecs: int64): int64'' | pub | Sendet ICMP-Ping und wartet auf Antwort | | ''EthernetHeaderCreate(dstMac: MacAddr, srcMac: MacAddr, ethertype: int64): EthernetHeader'' | pub | Erstellt Ethernet-Frame-Header | | ''ARPMakeRequest(senderMac: MacAddr, senderIP: int64, targetIP: int64): ARPPacket'' | pub | Erstellt ARP-Request-Paket | | ''ARPMakeReply(senderMac: MacAddr, senderIP: int64, targetMac: MacAddr, targetIP: int64): ARPPacket'' | pub | Erstellt ARP-Reply-Paket | | ''ARPSerializePacket(eth: EthernetHeader, arp: ARPPacket, buf: int64): int64'' | pub | Serialisiert ARP-Paket in Puffer | | ''MacBroadcast(): MacAddr'' | pub | Gibt Broadcast-MAC-Adresse zurück | | ''IPPack(a: int64, b: int64, c: int64, d: int64): int64'' | pub | Packt vier Oktette zu IPv4-Adresse | | ''IPUnpack(ip: int64): IPAddr'' | pub | Entpackt IPv4-Adresse in Oktette | ---- ===== Nicht-blockierende Sockets ===== ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''SocketSetNonBlocking(fd: int64): int64'' | pub | Setzt Socket auf nicht-blockierenden Modus | | ''SocketSetBlocking(fd: int64): int64'' | pub | Setzt Socket auf blockierenden Modus | | ''SocketIsNonBlocking(fd: int64): bool'' | pub | Prüft ob Socket nicht-blockierend ist | ==== PollFD (struct) ==== ^ Feld ^ Typ ^ | ''fd'' | ''int64'' | | ''events'' | ''int16'' | | ''revents'' | ''int16'' | ---- ===== Externe Funktionen ===== Extern deklarierte Funktionen (aus C-Bibliotheken): ^ Signatur ^ Beschreibung ^ | ''sys_poll(fds: int64, nfds: int64, timeout: int64): int64'' | Wartet auf Ereignisse mehrerer Deskriptoren | | ''sys_select(nfds: int64, readfds: int64, writefds: int64, exceptfds: int64, timeout: int64): int64'' | Multiplext I/O auf mehrere Deskriptoren | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''SocketPoll(fds: int64, nfds: int64, timeout: int64): int64'' | pub | Wartet auf Ereignisse via poll() | | ''PollFDReadable(fds: int64, index: int64): bool'' | pub | Prüft ob Deskriptor lesbar ist | | ''PollFDWritable(fds: int64, index: int64): bool'' | pub | Prüft ob Deskriptor schreibbar ist | | ''PollFDError(fds: int64, index: int64): bool'' | pub | Prüft ob Deskriptor Fehler hat | | ''FDSetZero(fdSet: int64)'' | pub | Leert fd_set-Struktur | | ''FDSet(fd: int64, fdSet: int64)'' | pub | Fügt Deskriptor zu fd_set hinzu | | ''FDClr(fd: int64, fdSet: int64)'' | pub | Entfernt Deskriptor aus fd_set | | ''FDIsSet(fd: int64, fdSet: int64): bool'' | pub | Prüft ob Deskriptor in fd_set gesetzt | ==== ConnectResult (struct) ==== ^ Feld ^ Typ ^ | ''success'' | ''bool'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''TCPConnectNonBlocking(ip: int64, port: int64, timeoutMs: int64): ConnectResult'' | pub | Verbindet nicht-blockierend mit Timeout | | ''SocketCanRead(fd: int64, timeoutMs: int64): int64'' | pub | Prüft Lesbarkeit innerhalb Timeout | | ''SocketCanWrite(fd: int64, timeoutMs: int64): int64'' | pub | Prüft Schreibbarkeit innerhalb Timeout | ==== UnixConn (struct) ==== ^ Feld ^ Typ ^ | ''fd'' | ''int64'' | ^ Signatur ^ Sichtbarkeit ^ Beschreibung ^ | ''UnixSocketNew(): UnixConn'' | pub | Erstellt neuen Unix-Domain-Socket | | ''UnixSocketBind(sock: UnixConn, path: int64): int64'' | pub | Bindet Unix-Socket an Dateipfad | | ''UnixSocketListen(sock: UnixConn, backlog: int64): int64'' | pub | Startet Verbindungsannahme am Socket | | ''UnixSocketAccept(sock: UnixConn): UnixConn'' | pub | Nimmt Unix-Socket-Verbindung entgegen | | ''UnixSocketConnect(path: int64): UnixConn'' | pub | Verbindet mit Unix-Domain-Socket-Pfad | | ''UnixSocketRead(conn: UnixConn, buf: int64, n: int64): int64'' | pub | Liest Bytes vom Unix-Socket | | ''UnixSocketWrite(conn: UnixConn, buf: int64, n: int64): int64'' | pub | Schreibt Bytes auf Unix-Socket | | ''UnixSocketClose(conn: UnixConn)'' | pub | Schließt Unix-Socket | | ''UnixSocketGetPeerCred(conn: UnixConn, pid: int64, uid: int64, gid: int64): int64'' | pub | Liest Peer-Prozessinformationen aus | | ''TCPConnectIPv6(ip6Hi: int64, ip6Lo: int64, port: int64): TCPConn'' | pub | Verbindet TCP über IPv6-Adresse | | ''TCPListenerBindIPv6(listener: TCPListener, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | pub | Bindet Listener an IPv6-Adresse | | ''TCPListenerNewIPv6(): TCPListener'' | pub | Erstellt IPv6-TCP-Listener-Socket | | ''UDPSocketNewIPv6(): UDPSocket'' | pub | Erstellt IPv6-UDP-Socket | | ''UDPSocketSendToIPv6(sock: UDPSocket, buf: int64, n: int64, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | pub | Sendet ein UDP-Datagramm an eine IPv6-Adresse; ''port'' in Host-Byte-Order | ---- ===== IPv6 ===== Die Unit deckt IPv6 durchgehend ab — von der Socket-Erzeugung bis zum Auslesen der Gegenstelle. Adressen werden als **zwei ''int64''-Hälften** übergeben (''ip6Hi'', ''ip6Lo''); die passenden Werte liefert [[lyx_-_programmiersprache:units:net:types|std.net.types]] mit ''IPv6MakeHi''/''IPv6MakeLo'', ''IPv6AnyHi''/''IPv6AnyLo'' und ''IPv6LoopbackHi''/''IPv6LoopbackLo''. ^ Signatur ^ Beschreibung ^ | ''SocketNewV6(): int64'' | neuen IPv6-TCP-Socket anlegen; ''fd >= 0'' bei Erfolg | | ''SocketNew6(): int64'' | Alias für ''SocketNewV6'' — der in der Spezifikation kanonische Name | | ''BindV6(fd: int64, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | an eine IPv6-Adresse binden; ''port'' in Host-Byte-Order, 0 bei Erfolg | | ''BindAddr6(fd: int64, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | Alias für ''BindV6'' | | ''ConnectV6(fd: int64, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | mit einer IPv6-Gegenstelle verbinden | | ''ConnectAddr6(fd: int64, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | Alias für ''ConnectV6'' | | ''UDPSocketBindIPv6(sock: UDPSocket, ip6Hi: int64, ip6Lo: int64, port: int64): int64'' | IPv6-UDP-Socket zum Empfangen an einen Port binden | | ''TCPListenerAcceptIPv6(listener: TCPListener, outHi: int64, outLo: int64, outPort: int64): TCPConn'' | eingehende IPv6-Verbindung annehmen | | ''UDPSocketRecvFromIPv6(sock: UDPSocket, buf: int64, n: int64, outHi: int64, outLo: int64, outPort: int64): int64'' | Datagramm empfangen und die Absenderadresse zurückgeben | | ''SocketGetPeerAddrIPv6(fd: int64, outHi: int64, outLo: int64, outPort: int64): int64'' | IPv6-Adresse der Gegenstelle lesen | | ''SocketGetOwnAddrIPv6(fd: int64, outHi: int64, outLo: int64, outPort: int64): int64'' | eigene lokale IPv6-Adresse lesen | Die drei ''out''-Parameter sind **Zeiger auf ''int64''**, nicht Rückgabewerte. Wer eine Angabe nicht braucht, übergibt dort ''0'' — die Funktion überspringt sie dann. > Zu jedem der drei Paare gibt es zwei Namen: ''SocketNewV6''/''SocketNew6'', ''BindV6''/''BindAddr6'', ''ConnectV6''/''ConnectAddr6''. Es sind echte Aliase — dieselbe Funktion, nur zweimal benannt. Die ''…Addr6''-Form ist die von der Spezifikation vorgesehene. ---- ===== Eigene und fremde Adresse abfragen ===== ^ Signatur ^ Beschreibung ^ | ''SocketGetOwnAddr(fd: int64, addrBuf: int64, addrLen: int64): int64'' | lokale Adresse des Sockets; ''addrBuf'' muss ''SOCKADDR_IN_SIZE'' groß sein | | ''SocketGetPeerAddr(fd: int64, addrBuf: int64, addrLen: int64): int64'' | Adresse der verbundenen Gegenstelle | Nützlich, wenn der Port vom Kernel vergeben wurde — nach einem ''Bind'' auf Port 0 steht die tatsächlich belegte Nummer erst hier. ---- ===== Verbindungen annehmen: blockierend oder nicht ===== ^ Signatur ^ Beschreibung ^ | ''AcceptBlocking(fd: int64, addrBuf: int64, addrLen: int64): int64'' | wartet, bis eine Verbindung vorliegt; setzt ''SOCK_CLOEXEC'' | | ''AcceptNonBlocking(fd: int64, addrBuf: int64, addrLen: int64): int64'' | kehrt sofort zurück; setzt ''SOCK_NONBLOCK'' und ''SOCK_CLOEXEC'' | Beide liefern einen neuen Deskriptor. Liegt bei ''AcceptNonBlocking'' keine Verbindung an, ist das Ergebnis **''-11''** (''-EAGAIN'') — das ist kein Fehler, sondern die übliche Antwort in einer Ereignisschleife (→ [[lyx_-_programmiersprache:units:net:epoll|std.net.epoll]]). Dass beide ''SOCK_CLOEXEC'' setzen, ist wichtiger als es aussieht: ohne dieses Flag erbt jeder mit ''fork''/''execve'' gestartete Kindprozess die offene Verbindung. ---- ===== Mehrere Datagramme in einem Syscall ===== ''sendmmsg'' und ''recvmmsg'' übertragen mehrere Nachrichten mit einem einzigen Systemaufruf. Bei hohen Paketraten spart das den größten Einzelposten — den Wechsel in den Kernel und zurück. ^ Signatur ^ Beschreibung ^ | ''MmsgAlloc(vlen: int64, iovOut: int64): int64'' | legt ''vec''- und ''iov''-Feld für ''vlen'' Einträge an; liefert den ''vec''-Zeiger, 0 bei Fehler | | ''MmsgSetBuf(iov: int64, idx: int64, buf: int64, bufLen: int64)'' | Datenpuffer für Eintrag ''idx'' eintragen | | ''SendMmsg(fd: int64, vec: int64, vlen: int64, flags: int64): int64'' | bis zu ''vlen'' Nachrichten senden | | ''RecvMmsg(fd: int64, vec: int64, vlen: int64, flags: int64): int64'' | bis zu ''vlen'' Nachrichten empfangen | | ''MmsgGetLen(vec: int64, idx: int64): int64'' | empfangene Bytezahl aus ''mmsghdr[idx].msg_len'' | | ''MmsgFree(vec: int64, iov: int64, vlen: int64)'' | beide Felder freigeben | ''iovOut'' ist ein ''alloc(8)''-Puffer, in den ''MmsgAlloc'' den ''iov''-Zeiger schreibt — die Funktion gibt also zwei Zeiger zurück, einen über den Rückgabewert und einen über diesen Parameter. Beide werden für ''MmsgFree'' gebraucht. Der Rückgabewert von ''SendMmsg''/''RecvMmsg'' ist die Zahl der **tatsächlich** übertragenen Nachrichten; sie kann kleiner als ''vlen'' sein. ---- ===== Socket-Optionen: was sich mit #1611 geändert hat ===== **Bis lyxc 1.1.1C lieferten alle zehn Options-Setter ''EFAULT'' zurück** und wirkten nicht: ''optval'' wurde als **Wert** statt als **Adresse** an ''setsockopt'' übergeben, der Kernel las an Adresse 1 ([[https://github.com/SEOLizer/LyX-Compiler/issues/1611|#1611]]). Betroffen waren ''TCPConnSetNodelay'', ''TCPConnSetKeepAlive'', ''TCPConnSetRecvBuf'', ''TCPConnSetSendBuf'', ''TCPConnSetReuseAddr'', ''TCPListenerSetReuseAddr'', ''TCPListenerSetReusePort'', ''UDPSocketSetReuseAddr'', ''UDPSocketSetRecvBuf'' und ''UDPSocketSetSendBuf''. **Schwerer wog der Lesepfad:** ''TCPConnGetError'' und ''UDPSocketGetError'' lasen den Fehlerstand nie und meldeten deshalb immer ''0'' — „kein Fehler". Im Connect-Pfad (''revents & POLLOUT'') galt eine Verbindung damit **immer** als erfolgreich, auch nach einem abgewiesenen Verbindungsversuch. Beide Richtungen laufen jetzt über je einen Helfer, damit die Frage „Wert oder Adresse" nur an einer Stelle beantwortet wird. Neu hinzugekommen ist ''UDPSocketSetBroadcast'' — die Option fehlte ganz, und ohne sie ist kein Rundruf möglich. ==== Zeitgrenzen für UDP ==== ''UDPSocketSetRecvTimeout(sock, sek, mikrosek)'' und ''UDPSocketSetSendTimeout(sock, sek, mikrosek)'' setzen ''SO_RCVTIMEO'' bzw. ''SO_SNDTIMEO''; Rückgabe ist ''0'' bei Erfolg, sonst der negative Fehlercode. Läuft die Zeit ab, liefert ''UDPSocketRecv'' einen negativen Wert (''EAGAIN''), statt für immer zu blockieren. Beide Setter brauchen eine ''timeval'' aus **zwei 64-Bit-Werten** — der Helfer für die einfachen ''int''-Optionen schreibt nur vier Byte und taugt hier nicht. Eingezogen wurden sie für ''std.net.dns'', wo eine ausbleibende Antwort den Aufrufer aufhängte ([[https://github.com/SEOLizer/LyX-Compiler/issues/1641|#1641]]). UDPSocketSetRecvTimeout(sock, 2, 0); // zwei Sekunden var n: int64 := UDPSocketRecv(sock, buf, 512, 0, 0); if (n < 0) { PrintLn("keine Antwort"); } Letzte Aktualisierung: 2026-08-19 — ''UDPSocketSetRecvTimeout''/''UDPSocketSetSendTimeout'' ergänzt ([[https://github.com/SEOLizer/LyX-Compiler/issues/1641|#1641]]). Vorherige Aktualisierung: 2026-08-18 — Options-Setter, Fehlerabfrage und ''UDPSocketSetBroadcast'' nachgezogen ([[https://github.com/SEOLizer/LyX-Compiler/issues/1611|#1611]]).