Socket Framework für Swift mit dem Swift -Paket -Manager. Arbeitet auf iOS, macOS und Linux.
swift-5.1-RELEASE Toolchain ( Mindestmaß für die neueste Version )swift-5.4-RELEASE Toolchain ( empfohlen )Notiz:
Wenn Sie einen UDP -Server auf iOS erstellen, müssen Sie möglicherweise einige Schritte ausführen:
So erstellen Sie Socket aus der Befehlszeile:
% cd <path-to-clone>
% swift build
So führen Sie die mitgelieferten Unit -Tests für Socket aus der Befehlszeile aus:
% cd <path-to-clone>
% swift build
% swift test
Um Bluesocket in ein Swift -Paket -Paket -Manager -Paket einzubeziehen, fügen Sie es dem in Ihrem Package.swift -Datei definierten dependencies hinzu. Sie können die Version mithilfe der majorVersion und minor Parameter auswählen. Zum Beispiel:
dependencies: [
.Package(url: "https://github.com/Kitura/BlueSocket.git", majorVersion: <majorVersion>, minor: <minor>)
]
Um Bluesocket in ein Projekt mit Karthago aufzunehmen, fügen Sie Ihrem Cartfile eine Zeile mit der Github -Organisation sowie der Projektnamen und der Version und der Version hinzu. Zum Beispiel:
github "Kitura/BlueSocket" ~> <majorVersion>.<minor>
Um Bluesocket in ein Projekt mit Cocoapods aufzunehmen, fügen Sie Ihrem Podfile nur BlueSocket hinzu, zum Beispiel:
platform :ios, '10.0'
target 'MyApp' do
use_frameworks!
pod 'BlueSocket'
end
Das erste, was Sie tun müssen, ist das Socket -Framework zu importieren. Dies geschieht durch Folgendes:
import Socket
Bluesocket unterstützt die folgenden Familien, Typen und Protokolle:
Socket.ProtocolFamily.inetSocket.ProtocolFamily.inet6Socket.ProtocolFamily.unixSocket.SocketType.streamSocket.SocketType.datagramSocket.SocketProtocol.tcpSocket.SocketProtocol.udpSocket.SocketProtocol.unixBluesocket bietet vier verschiedene Werksmethoden, mit denen eine Instanz erstellt wird. Diese sind:
create() - Dies erstellt einen vollständig konfigurierten Standard -Socket. Ein Standard -Socket wird mit family: .inet , type: .stream und proto: .tcp .create(family family: ProtocolFamily, type: SocketType, proto: SocketProtocol) - Mit dieser API können Sie eine konfigurierte Socket -Instanz erstellen, die für Ihre Anforderungen angepasst ist. Sie können die Protokollfamilie, das Socket -Typ und das Sockelprotokoll anpassen.create(connectedUsing signature: Signature) - Mit dieser API können Sie eine Socket -Instanz erstellen und versuchen, eine Verbindung zu einem Server herzustellen, basierend auf den Informationen, die Sie in der Socket.Signature übergeben.create(fromNativeHandle nativeHandle: Int32, address: Address?) - Mit dieser API können Sie einen nativen Dateideskriptor einwickeln, der einen vorhandenen Socket in einer neuen Instanz von Socket beschreibt. Mit Bluesocket können Sie die Größe des Lesepuffers festlegen, den er verwendet. Abhängig von den Anforderungen der Anwendung können Sie sie dann auf einen höheren oder niedrigeren Wert ändern. Die Standardeinstellung wird auf Socket.SOCKET_DEFAULT_READ_BUFFER_SIZE gesetzt 4096 Die minimale Lesepuffergröße ist Socket.SOCKET_MINIMUM_READ_BUFFER_SIZE , die auf 1024 eingestellt ist. Im Folgenden zeigt, wie Sie die Lesepuffergröße ändern (Ausnahmebehandlung für die Kürze):
let mySocket = try Socket.create()
mySocket.readBufferSize = 32768
Das obige Beispiel legt die Standard -Lesepuffergröße auf 32768 fest. Diese Einstellung sollte vor der Verwendung der Socket -Instanz erstmals durchgeführt werden.
Um den Sockel einer offenen Instanz zu schließen, wird die folgende Funktion bereitgestellt:
close() - Diese Funktion führt die erforderlichen Aufgaben aus, um einen offenen Sockel sauber zu schließen.Um Bluesocket zu verwenden, um eine Verbindung auf einem Socket zu hören, wird die folgende API bereitgestellt:
listen(on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG, allowPortReuse: Bool = true, node: String? = nil) Der erste port ist der Port zum Anhören verwendet. Mit dem zweiten Parameter, maxBacklogSize können Sie die Größe der Warteschlange festlegen, die ausstehende Verbindungen hält. Die Funktion bestimmt die entsprechende Socket -Konfiguration basierend auf dem angegebenen port . Für die Bequemlichkeit auf macOS kann der konstante Socket.SOCKET_MAX_DARWIN_BACKLOG so eingestellt werden, dass die maximal zulässige Rückstandgröße verwendet wird. Der Standardwert für alle Plattformen ist Socket.SOCKET_DEFAULT_MAX_BACKLOG , der derzeit auf 50 eingestellt ist. Für die Verwendung von Server kann es erforderlich sein, diesen Wert zu erhöhen. Um die Wiederverwendung des Höranschlusses zu ermöglichen, können Sie allowPortReuse für true sind. Wenn Sie auf false festgelegt sind, tritt ein Fehler auf, wenn Sie versuchen, einen bereits verwendeten Port zuzuhören. Das DEFAULT besteht darin, die Port -Wiederverwendung allow . Der letzte Parameter, node , kann verwendet werden, um eine bestimmte Adresse zu hören. Der übergebene Wert ist eine optionale Zeichenfolge, die die numerische Netzwerkadresse enthält (für IPv4, Nummern und Punkte, für IPv6, Hexidecimal String). Das DEFAULT besteht darin, nach einer geeigneten Schnittstelle zu suchen. Wenn node nicht ordnungsgemäß formatiert ist, wird ein Socket_err_Getaddrinfo_Failed -Fehler zurückgegeben. Wenn node ordnungsgemäß formatiert ist, die angegebene Adresse nicht verfügbar ist, wird ein Socket_err_Bind_Failed zurückgegeben.listen(on path: String, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) Diese API kann nur mit der .unix -Protokollfamilie verwendet werden. Der erste path ist der Pfad, der verwendet wird, um anzuhören. Mit dem zweiten Parameter, maxBacklogSize können Sie die Größe der Warteschlange festlegen, die ausstehende Verbindungen hält. Die Funktion bestimmt die entsprechende Socket -Konfiguration basierend auf dem angegebenen port . Für die Bequemlichkeit auf macOS kann der konstante Socket.SOCKET_MAX_DARWIN_BACKLOG so eingestellt werden, dass die maximal zulässige Rückstandgröße verwendet wird. Der Standardwert für alle Plattformen ist Socket.SOCKET_DEFAULT_MAX_BACKLOG , der derzeit auf 50 eingestellt ist. Für die Verwendung von Server kann es erforderlich sein, diesen Wert zu erhöhen. Das folgende Beispiel erstellt eine Standard Socket -Instanz und startet dann sofort an Port 1337 . HINWEIS: Ausnahmebehandlung für die Kürze weggelassen, finden Sie im vollständigen Beispiel unten ein Beispiel für die Ausnahmebehandlung.
var socket = try Socket . create ( )
try socket . listen ( on : 1337 )Wenn ein Hörbuchse eine eingehende Verbindungsanforderung erkennt, wird die Steuerung an Ihr Programm zurückgegeben. Sie können dann entweder die Verbindung akzeptieren oder weiterzuhören oder beides weiterhin, wenn Ihre Bewerbung multi-thread ist. Bluesocket unterstützt zwei verschiedene Arten, eine eingehende Verbindung zu akzeptieren. Sie sind:
acceptClientConnection(invokeDelegate: Bool = true) - Diese Funktion akzeptiert die Verbindung und gibt eine neue Socket -Instanz zurück, die auf dem neu verbundenen Socket basiert. Die Instanz, die nicht betroffen war. Wenn invokeDelegate false ist und der Socket über einen SSLService -Delegate angeschlossen ist, müssen Sie die invokeDelegateOnAccept -Methode unter Verwendung der Socket -Instanz aufrufen, die von dieser Funktion zurückgegeben wird.invokeDelegateOnAccept(for newSocket: Socket) - Wenn die Socket -Instanz über einen SSLService -Delegierten verfügt, werden die Delegierten die Akzeptanz von Funktionen zur Durchführung von SSL -Verhandlungen berücksichtigt. Es sollte mit der Socket -Instanz aufgerufen werden, die von acceptClientConnection zurückgegeben wird. Diese Funktion bringt eine Ausnahme, wenn sie mit der falschen Socket -Instanz aufgerufen wird, die mehrmals aufgerufen wird oder wenn die Socket -Instanz keinen SSLService -Delegierten hat.acceptConnection() - Diese Funktion akzeptiert die eingehende Verbindung, wodurch der vorhandene Hörbuchsen ersetzt und geschlossen wird . Die Eigenschaften, die früher mit der Hörsteck in Verbindung gebracht wurden, werden durch die Eigenschaften ersetzt, die für den neu verbundenen Sockel relevant sind. Zusätzlich zum create(connectedUsing:) oben beschriebene Fabrikmethode unterstützt Bluesocket drei zusätzliche Instanzfunktionen, um eine Socket -Instanz an einen Server anzuschließen. Sie sind:
connect(to host: String, port: Int32, timeout: UInt = 0) - Mit dieser API können Sie eine Verbindung zu einem Server basierend auf dem von Ihnen angegebenen hostname und port herstellen. Hinweis: Eine exception wird von dieser Funktion ausgelöst, wenn der Wert des port nicht im Bereich 1-65535 liegt. Optional können Sie timeout auf die Anzahl der Millisekunden einstellen, um auf die Verbindung zu warten. Hinweis: Wenn sich der Socket im Blockierungsmodus befindet, wird er vorübergehend in den Nicht-Blocking-Modus geändert, wenn eine timeout größer als Null (0) bereitgestellt wird. Der zurückgegebene Socket wird auf seine ursprüngliche Einstellung zurückgesetzt (Blockierung oder nicht blockierende) . Wenn der Sockel auf nicht blockierende und kein Zeitüberschreitungswert bereitgestellt wird, wird eine Ausnahme geworfen. Alternativ können Sie den Socket nach erfolgreichem Verbinden auf nicht blockierende Einstellung einstellen.connect(to path: String) - Diese API kann nur mit der .unix -Protokollfamilie verwendet werden. Sie können eine Verbindung zu einem Server basierend auf dem von Ihnen angegebenen path herstellen.connect(using signature: Signature) - Mit dieser API können Sie die Verbindungsinformationen angeben, indem Sie einen Socket.Signature angeben. Signaturinstanz mit den Informationen. Weitere Informationen finden Sie in Socket.Signature in Socket.wift .Bluesocket unterstützt vier verschiedene Möglichkeiten zum Lesen von Daten aus einem Socket. Diese sind (in empfohlener Bestellung):
read(into data: inout Data) - Diese Funktion liest alle in einem Socket verfügbaren Daten und gibt sie in das übergebene Data zurück.read(into data: NSMutableData) - Diese Funktion liest alle in einem Socket verfügbaren Daten und gibt sie im NSMutableData -Objekt zurück, das übergeben wurde.readString() - Diese Funktion liest alle in einem Socket verfügbaren Daten und gibt sie als String zurück. Ein nil wird zurückgegeben, wenn keine Daten zum Lesen verfügbar sind.read(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int, truncate: Bool = false) - Mit dieser Funktion können Sie Daten in einen Puffer einer bestimmten Größe lesen, indem Sie einen unsicheren Zeiger auf diesen Puffer und eine ganze Zahl der Denots der Größe dieses Puffers bereitstellen. Diese API bufSize zusätzlich zu anderen Arten truncate = true Ausnahmen) wirft einen Socket.SOCKET_ERR_RECV_BUFFER_TOO_SMALL . Wenn truncate = false , müssen Sie erneut mit der ordnungsgemäßen Puffergröße anrufen (siehe Error.bufferSizeNeeded .readString() können Null zurückgeben (0). Dies kann darauf hinweisen, dass die Fernverbindung geschlossen wurde oder darauf hinweist, dass der Sockel blockiert wird (vorausgesetzt, Sie haben das Blockieren ausgeschaltet). Um zwischen den beiden zu unterscheiden, kann die Eigenschaft remoteConnectionClosed überprüft werden. true der Socket Remote -Partner die Verbindung geschlossen hat, sollte diese Socket -Instanz geschlossen werden.Neben dem Lesen aus einer Steckdose liefert Bluesocket auch vier Methoden zum Schreiben von Daten in einen Sockel. Diese sind (in empfohlener Bestellung):
write(from data: Data) - Diese Funktion schreibt die im Data enthaltenen Daten in den Socket.write(from data: NSData) - Diese Funktion schreibt die im NSData -Objekt enthaltenen Daten in den Socket.write(from string: String) - Diese Funktion schreibt die in der String enthaltenen Daten, die in den Socket bereitgestellt wurden.write(from buffer: UnsafeRawPointer, bufSize: Int) - Diese Funktion schreibt die Daten, die im Puffer der angegebenen Größe enthalten sind, indem Sie einen unsicheren Zeiger auf diesen Puffer und eine Ganzzahl bereitstellen, die die Größe dieses Puffer bezeichnet.Bluesocket unterstützt drei verschiedene Möglichkeiten, um eingehende Datagramme zu hören. Diese sind (in empfohlener Bestellung):
listen(forMessage data: inout Data, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - Diese Funktion hört auf ein eingehendes Datagramm zu, liest es und gibt es in das übergebene Data zurück. Es gibt ein Tupel zurück, das die Anzahl der gelesenen Bytes und die Address des Ursprung der Daten enthält.listen(forMessage data: NSMutableData, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - Diese Funktion hört auf ein eingehendes Datagramm an, liest es und gibt es in das übergebene NSMutableData -Objekt zurück. Es gibt ein Tupel zurück, das die Anzahl der gelesenen Bytes und die Address des Ursprung der Daten enthält.listen(forMessage buffer: UnsafeMutablePointer<CChar>, bufSize: Int, on port: Int, maxBacklogSize: Int = Socket.SOCKET_DEFAULT_MAX_BACKLOG) - Diese Funktion hört auf ein eingehendes Datagramm zu, liest es und gibt es in das übergebene Data zurück. Es gibt ein Tupel zurück, das die Anzahl der gelesenen Bytes und die Address des Ursprung der Daten enthält.port . Durch die Festlegung des Wertes des port auf Null (0) wird die Funktion einen geeigneten freien Port ermittelt.maxBacklogSize können Sie die Größe der Warteschlange festlegen, die anhängige Verbindungen hält. Die Funktion bestimmt die entsprechende Socket -Konfiguration basierend auf dem angegebenen port . Für die Bequemlichkeit auf macOS kann der konstante Socket.SOCKET_MAX_DARWIN_BACKLOG so eingestellt werden, dass die maximal zulässige Rückstandgröße verwendet wird. Der Standardwert für alle Plattformen ist Socket.SOCKET_DEFAULT_MAX_BACKLOG , der derzeit auf 50 eingestellt ist. Für die Verwendung von Server kann es erforderlich sein, diesen Wert zu erhöhen.Bluesocket unterstützt drei verschiedene Möglichkeiten, eingehende Datagramme zu lesen. Diese sind (in empfohlener Bestellung):
readDatagram(into data: inout Data) - Diese Funktion liest ein eingehendes Datagramm und gibt es im übergebenen Data zurück. Es gibt ein Tupel zurück, das die Anzahl der gelesenen Bytes und die Address des Ursprung der Daten enthält.readDatagram(into data: NSMutableData) - Diese Funktion liest ein eingehendes Datagramm und gibt es in das übergebene NSMutableData -Objekt zurück. Es gibt ein Tupel zurück, das die Anzahl der gelesenen Bytes und die Address des Ursprung der Daten enthält.readDatagram(into buffer: UnsafeMutablePointer<CChar>, bufSize: Int) - Diese Funktion liest ein eingehendes Datagramm und gibt es im übergebenen Data zurück. Es gibt ein Tupel zurück, das die Anzahl der gelesenen Bytes und die Address des Ursprung der Daten enthält. Wenn die Menge der gelesenen Daten mehr als nur bufSize ist, wird nur bufSize zurückgegeben. Der Rest der gelesenen Daten wird verworfen.Bluesocket liefert auch vier Methoden zum Schreiben von Datagrammen in einen Sockel. Diese sind (in empfohlener Bestellung):
write(from data: Data, to address: Address) - Diese Funktion schreibt das im Data enthaltene Datagramm in den Socket.write(from data: NSData, to address: Address) - Diese Funktion schreibt das im NSData -Objekt enthaltene Datagramm in den Socket.write(from string: String, to address: Address) - Diese Funktion schreibt das in der String enthaltene Datagramm, das in den Socket bereitgestellt wurde.write(from buffer: UnsafeRawPointer, bufSize: Int, to address: Address) - Diese Funktion schreibt die Daten, die im Puffer der angegebenen Größe enthalten sind, indem ein unsicherer Zeiger auf diesen Puffer und eine Ganzzahl bereitgestellt wird, die die Größe dieses Puffers bezeichnet.address Parameter die Adresse für das Ziel, an das Sie den Datagramm senden. Die oben genannten Lese- und Schreib -APIs, die entweder NSData oder NSMutableData verwenden, wird wahrscheinlich in nicht so ferner Zukunft veraltet sein.
hostnameAndPort(from address: Address) - Diese Klassenfunktion bietet die Möglichkeit, den Hostnamen und den Port aus einem bestimmten Socket.Address zu extrahieren. Nach erfolgreicher Fertigstellung wird ein Tupel, das den hostname und port enthält, zurückgegeben.checkStatus(for sockets: [Socket]) - Mit dieser Klassenfunktion können Sie den Status einer Reihe von Socket -Instanzen überprüfen. Nach Abschluss wird ein Tupel mit zwei Socket zurückgegeben. Das erste Array enthält die Socket -Instanzen, die Daten zur Verfügung stehen, und das zweite Array enthält Socket -Instanzen, an die geschrieben werden kann. Diese API blockiert nicht . Es wird den Status jeder Socket -Instanz überprüft und dann die Ergebnisse zurückgeben.wait(for sockets: [Socket], timeout: UInt, waitForever: Bool = false) - Diese Klassenfunktion ermöglicht die Überwachung eines Arrays von Socket -Instanzen und wartet, dass entweder eine Zeitüberschreitung auftritt oder Daten in einem der überwachten Socket -Instanzen lesbar sind. Wenn eine Zeitüberschreitung von Null (0) angegeben ist, überprüft diese API jeden Socket und kehrt sofort zurück. Andernfalls wartet es, bis entweder das Timeout abläuft oder die Daten von einem oder mehreren der überwachten Socket -Instanzen lesbar sind. Wenn eine Zeitüberschreitung auftritt, wird diese API nil zurückgegeben. Wenn Daten zu einem oder mehreren der überwachten Socket -Instanzen verfügbar sind, werden diese Instanzen in einem Array zurückgegeben. Wenn das waitForever -Flag auf true eingestellt ist, wartet die Funktion auf unbestimmte Zeit darauf, dass Daten unabhängig vom angegebenen Zeitüberschreitungswert verfügbar werden.createAddress(host: String, port: Int32) - Diese Klassenfunktion ermöglicht die Erstellung von Address bei einem host und port . Nach dem Erfolg gibt diese Funktion eine Address oder nil zurück, wenn der angegebene host nicht vorhanden ist.isReadableOrWritable(waitForever: Bool = false, timeout: UInt = 0) - Mit dieser Instanzfunktion können Sie feststellen, ob eine Socket -Instanz lesbar und/oder beschreibbar ist. Ein Tupel wird zurückgegeben, das zwei Bool -Werte enthält. Das erste, falls wahr ist, gibt an, dass die Socket -Instanz Daten zum Lesen hat. Das zweite gibt an, wenn wahr, dass die Socket -Instanz geschrieben werden kann. waitForever wenn es zutrifft, wenn diese Routine wartet, bis der Socket entweder lesbar oder beschreibbar ist oder ein Fehler auftritt. Wenn falsch, gibt der timeout -Parameter an, wie lange warten soll. Wenn für den Zeitüberschreitungswert ein Wert von Null (0) angegeben ist, überprüft diese Funktion den aktuellen Status und gibt sofort zurück. Diese Funktion gibt ein Tupel mit zwei Booleschen zurück, die erste readable und die zweite, writable . Sie sind auf wahr eingestellt, wenn der Socket entweder lesbar oder beschreibbar ist. Wenn keiner auf wahr ist, ist eine Auszeit eingetreten. Hinweis: Wenn Sie versuchen, in einen neu verbundenen Socket zu schreiben, sollten Sie sicherstellen, dass sie beschreibbar ist, bevor Sie den Betrieb versuchen.setBlocking(shouldBlock: Bool) - Mit dieser Instanzfunktion können Sie steuern, ob diese Socket -Instanz im Blockierungsmodus platziert werden soll oder nicht. Hinweis: Alle Socket -Instanzen werden standardmäßig im Blockierungsmodus erstellt.setReadTimeout(value: UInt = 0) - Mit dieser Instanzfunktion können Sie eine Zeitüberschreitung für Lesevorgänge festlegen. value ist ein UInt , der die Zeit angibt, dass die Lesevorrichtung vor der Rückkehr warten kann. Im Falle einer Zeitüberschreitung wird die Leseoperation 0 Bytes gelesen und errno wird auf EAGAIN eingestellt.setWriteTimeout(value: UInt = 0) - Mit dieser Instanzfunktion können Sie eine Zeitüberschreitung für Schreibvorgänge festlegen. value ist ein UInt Die Angabe der Zeit, in der die Schreibvor Operationen warten, bevor Sie zurückkehren. Im Falle einer Zeitüberschreitung wird der Schreibvorgang 0 geschriebene Bytes zurückgeben und errno wird für TCP und Unix -Sockets auf EAGAIN eingestellt. Für UDP wird der Schreibvorgang unabhängig vom Zeitüberschreitungswert erfolgreich sein .udpBroadcast(enable: Bool) - Mit dieser Instanzfunktion wird der Broadcast -Modus in einem UDP -Socket aktiviert. Pass true , um die Sendung zu aktivieren, false zu deaktivieren. Diese Funktion bringt eine Ausnahme, wenn die Socket -Instanz kein UDP -Socket ist. Das folgende Beispiel zeigt, wie ein relativ einfacher Echo-Server mit Multi-Threaded mit der neuen GCD based Versand -API erstellt wird. Was folgt, ist Code für einen einfachen Echo -Server, auf den einst ausgeführt wurde, kann über telnet ::1 1337 zugegriffen werden.
import Foundation
import Socket
import Dispatch
class EchoServer {
static let quitCommand : String = " QUIT "
static let shutdownCommand : String = " SHUTDOWN "
static let bufferSize = 4096
let port : Int
var listenSocket : Socket ? = nil
var continueRunningValue = true
var connectedSockets = [ Int32 : Socket ] ( )
let socketLockQueue = DispatchQueue ( label : " com.kitura.serverSwift.socketLockQueue " )
var continueRunning : Bool {
set ( newValue ) {
socketLockQueue . sync {
self . continueRunningValue = newValue
}
}
get {
return socketLockQueue . sync {
self . continueRunningValue
}
}
}
init ( port : Int ) {
self . port = port
}
deinit {
// Close all open sockets...
for socket in connectedSockets . values {
socket . close ( )
}
self . listenSocket ? . close ( )
}
func run ( ) {
let queue = DispatchQueue . global ( qos : . userInteractive )
queue . async { [ unowned self ] in
do {
// Create an IPV6 socket...
try self . listenSocket = Socket . create ( family : . inet6 )
guard let socket = self . listenSocket else {
print ( " Unable to unwrap socket... " )
return
}
try socket . listen ( on : self . port )
print ( " Listening on port: ( socket . listeningPort ) " )
repeat {
let newSocket = try socket . acceptClientConnection ( )
print ( " Accepted connection from: ( newSocket . remoteHostname ) on port ( newSocket . remotePort ) " )
print ( " Socket Signature: ( String ( describing : newSocket . signature ? . description ) ) " )
self . addNewConnection ( socket : newSocket )
} while self . continueRunning
}
catch let error {
guard let socketError = error as? Socket . Error else {
print ( " Unexpected error... " )
return
}
if self . continueRunning {
print ( " Error reported: n ( socketError . description ) " )
}
}
}
dispatchMain ( )
}
func addNewConnection ( socket : Socket ) {
// Add the new socket to the list of connected sockets...
socketLockQueue . sync { [ unowned self , socket ] in
self . connectedSockets [ socket . socketfd ] = socket
}
// Get the global concurrent queue...
let queue = DispatchQueue . global ( qos : . default )
// Create the run loop work item and dispatch to the default priority global queue...
queue . async { [ unowned self , socket ] in
var shouldKeepRunning = true
var readData = Data ( capacity : EchoServer . bufferSize )
do {
// Write the welcome string...
try socket . write ( from : " Hello, type 'QUIT' to end session n or 'SHUTDOWN' to stop server. n " )
repeat {
let bytesRead = try socket . read ( into : & readData )
if bytesRead > 0 {
guard let response = String ( data : readData , encoding : . utf8 ) else {
print ( " Error decoding response... " )
readData . count = 0
break
}
if response . hasPrefix ( EchoServer . shutdownCommand ) {
print ( " Shutdown requested by connection at ( socket . remoteHostname ) : ( socket . remotePort ) " )
// Shut things down...
self . shutdownServer ( )
return
}
print ( " Server received from connection at ( socket . remoteHostname ) : ( socket . remotePort ) : ( response ) " )
let reply = " Server response: n ( response ) n "
try socket . write ( from : reply )
if ( response . uppercased ( ) . hasPrefix ( EchoServer . quitCommand ) || response . uppercased ( ) . hasPrefix ( EchoServer . shutdownCommand ) ) &&
( !response . hasPrefix ( EchoServer . quitCommand ) && !response . hasPrefix ( EchoServer . shutdownCommand ) ) {
try socket . write ( from : " If you want to QUIT or SHUTDOWN, please type the name in all caps. ? n " )
}
if response . hasPrefix ( EchoServer . quitCommand ) || response . hasSuffix ( EchoServer . quitCommand ) {
shouldKeepRunning = false
}
}
if bytesRead == 0 {
shouldKeepRunning = false
break
}
readData . count = 0
} while shouldKeepRunning
print ( " Socket: ( socket . remoteHostname ) : ( socket . remotePort ) closed... " )
socket . close ( )
self . socketLockQueue . sync { [ unowned self , socket ] in
self . connectedSockets [ socket . socketfd ] = nil
}
}
catch let error {
guard let socketError = error as? Socket . Error else {
print ( " Unexpected error by connection at ( socket . remoteHostname ) : ( socket . remotePort ) ... " )
return
}
if self . continueRunning {
print ( " Error reported by connection at ( socket . remoteHostname ) : ( socket . remotePort ) : n ( socketError . description ) " )
}
}
}
}
func shutdownServer ( ) {
print ( " n Shutdown in progress... " )
self . continueRunning = false
// Close all open sockets...
for socket in connectedSockets . values {
self . socketLockQueue . sync { [ unowned self , socket ] in
self . connectedSockets [ socket . socketfd ] = nil
socket . close ( )
}
}
DispatchQueue . main . sync {
exit ( 0 )
}
}
}
let port = 1337
let server = EchoServer ( port : port )
print ( " Swift Echo Server Sample " )
print ( " Connect with a command line window by entering 'telnet ::1 ( port ) ' " )
server . run ( ) Dieser Server kann erstellt werden, indem das folgende Package.swift mit Swift 4 angegeben wird.
import PackageDescription
let package = Package (
name : " EchoServer " ,
dependencies : [
. package ( url : " https://github.com/Kitura/BlueSocket.git " , from : " 1.0.8 " ) ,
] ,
targets : [
. target (
name : " EchoServer " ,
dependencies : [
" Socket "
] ) ,
]
) Oder wenn Sie Swift 3 noch verwenden, indem Sie die folgende Package.swift -Datei angeben.
import PackageDescription
let package = Package (
name : " EchoServer " ,
dependencies : [
. Package ( url : " https://github.com/Kitura/BlueSocket.git " , majorVersion : 1 , minor : 0 ) ,
] ,
exclude : [ " EchoServer.xcodeproj " ]
) Die folgende Befehlssequenz erstellt und führt den Echo -Server unter Linux aus. Wenn Sie auf MacOS oder mit einer neueren Toolchain als 8/18 Toolchain ausgeführt werden, können Sie den -Xcc -fblocks -Schalter weglassen, da er nicht mehr benötigt wird.
$ swift build -Xcc -fblocks
$ .build/debug/EchoServer
Swift Echo Server Sample
Connect with a command line window by entering 'telnet ::1 1337'
Listening on port: 1337
Wir lieben es, serverseitig und kitura zu sprechen. Treten Sie unserem Lock an, um das Team zu treffen!
Diese Bibliothek ist unter Apache 2.0 lizenziert. Der vollständige Lizenztext ist in der Lizenz erhältlich.