Einführung in Swift / C Bridge mit der Geschichte der Portierung von Echo Server mit libuv

Ich wusste, dass ich mit C-Sprachbibliotheken direkt von Swift aus arbeiten konnte, aber ich hatte es vorher noch nicht getan, daher ist es ein Tutorial für libuv uvbook tcp-echo-server Ich möchte nach Swift portieren, um mit der C-Sprachbrücke zu beginnen.

Umgebung

Dieses Mal werde ich Xcode auf dem Mac verwenden, um den TCP-Echo-Server zu portieren. Der Quellcode ist hier https://github.com/yokochie/EchoServer-Sample

Die Xcode-Version ist 7.2 und die Swift-Version ist 2.1.1.

Installieren Sie libuv

libuv ist erforderlich, um den TCP-Echo-Server von libuv zu portieren. Die Installation ist mit Homebrew einfach.

$ brew install --HEAD libuv

Nach der Installation befinden sich die erforderlichen Dateien in / usr / local / {include, lib}.

$ ls /usr/local/include/uv*.h
/usr/local/include/uv-darwin.h		/usr/local/include/uv-threadpool.h	/usr/local/include/uv-version.h
/usr/local/include/uv-errno.h		/usr/local/include/uv-unix.h		/usr/local/include/uv.h
$ ls /usr/local/lib/libuv*
/usr/local/lib/libuv.1.dylib	/usr/local/lib/libuv.a		/usr/local/lib/libuv.dylib

Erstellen eines Xcode-Projekts

Erstellen Sie ein Command Line Tool-Projekt unter Bezugnahme auf den Artikel Erstellen eines Paketmonitors mit Swift und Libpcap | Developers.IO.

Um libuv zu verwenden, fügen Sie zuerst libuv.dylib aus den Projekteinstellungen hinzu und fügen Sie / usr / local / include /, / usr / local / lib zu Header-Suchpfad und Bibliothekssuchpfad im Suchpfad hinzu. LibrarySetting.png SearchPath.png

Lassen Sie libuv aufrufen

Erstellen Sie Bridging-Header.h auf irgendeine Weise (einfach, eine neue Objective-C-Datei zu erstellen und zu löschen),

#include <uv.h>

Hinzufügen.

Anschließend wird die libuv-Methode vorgeschlagen, wie in der folgenden Abbildung dargestellt. suggest.png

Einführung in die Swift / C Bridge

https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift Wagen Sie die Implementierung in C-Sprache (https://github.com/nikhilm/uvbook/blob/master/code/tcp -Ich habe etwas Ähnliches gepostet wie (echo-server / main.c). Wie in der Abbildung am Ende der Umgebungskonstruktion gezeigt, kann die Funktion so aufgerufen werden, wie sie ist. Wenn die Variablentypen richtig übereinstimmen, kann sie einfach portiert werden. Ich denke, es wird einfacher zu verstehen sein, wenn Sie sie beim Lesen dieses Artikels vergleichen.

Informationen zum Variablentyp

[Verwenden von Swift mit Cocoa und Objective-C (Swift 2.1): Interaktion mit C-APIs](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/ Es wird in einen Typ konvertiert, der mit dem Akronym C beginnt, z. B. "CChar", "CInt" (wie in doc / uid / TP40014216-CH8-ID17 beschrieben). (Der in XCode vorgeschlagene Typ ist jedoch ein Typ mit einer expliziten Anzahl von Bits, z. B. "Int8" oder "Int32".)

Für Zeiger wird "Typ *" zu "UnsafeMutablePointer " und "const Type *" zu "UnsafePointer ". Außerdem ändert sich "NULL" in "Null".

Basierend auf normaler Typkonvertierung und Zeigertypkonvertierung

int * hoge = NULL

Aber

var hoge: UnsafeMutablePointer<CInt> = nil

Wird sein.

Über den Umgang mit Zeigern

Die C-Struktur kann so wie sie ist als Swift-Struktur verwendet werden, aber wenn es sich um eine Funktion handelt, die einen Zeiger auf eine Variable erfordert Ist in Ordnung, wenn Sie "&" voranstellen (genauso, als hätten Sie der Methodendefinition "inout" vorangestellt). Der Quellcode für diese Zeit lautet main.swift: 66.

uv_ip4_addr("0.0.0.0", CInt(DEFAULT_PORT), &addr)

Diese Technik scheint jedoch nicht zu funktionieren, wenn Abgüsse auftreten. https://github.com/nikhilm/uvbook/blob/master/code/tcp-echo-server/main.c#L64

uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);

Das Hinzufügen von "&" und die Portierung stimmten nicht mit dem Typ überein und führten zu einem Kompilierungsfehler. Daher [withUnsafePointer -Funktion](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_StandardLibrary_Functions/index.html#//apple_ref/swift/func/s:FSs17withUnsafePointerF0_Sf_Uf_Sf_Fr_Sf_Gf_Sn_ Ich gieße mit dem Initialisierer.

withUnsafePointer(&addr) {
    uv_tcp_bind(&server, UnsafePointer<sockaddr>($0), 0)
}

(UnsafePointer Structure Reference enthält nichts, was den Typ der Variablen im Zeiger direkt übernehmen kann. Bitte seien Sie vorsichtig)

Obwohl libuv häufig Rückruffunktionen verwendet, war es möglich, global deklarierte Funktionen so anzugeben, wie sie sind. Zum Beispiel nimmt die Funktion "uv_listen" am Ende des Arguments "void (* uv_connection_cb) (uv_stream_t * server, int status)". Https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift#L73, implementiert in Swift, akzeptiert func on_new_connect (Server: UnsafeMutablePointer <uv_stream_t>, Status: CInt) wie es ist Ich kann es bestehen.

Handhabung innerhalb des Zeigers

In C können Sie die Operatoren "*" und "->" verwenden, um Variablen in Zeigern zu referenzieren. In Swift verwenden Sie jedoch die Eigenschaft "memory" (https://github.com/yokochie/EchoServer). -Verwendet in Sample / blob / master / EchoServer / main.swift # L13) Verwenden Sie die Methode "UnsafeMutablePointer .alloc (size)", um Speicher zuzuweisen, und die Methode "destory", um ihn freizugeben.

Andere

Es scheint, dass die Swift Standard Library keine Funktion zum Ausgeben an die Standardfehlerausgabe hat, daher gebe ich dieses Mal eine Fehleranweisung an die Standardausgabe aus. Es scheint, dass Sie dies tun können, indem Sie OutputStream wie unter http://ericasadun.com/2015/06/09/swift-2-0-how-to-print/ beschrieben öffnen.

Implementierungsbestätigung

Drücken Sie zum Ausführen ⌘R auf Xcode. Dann im Terminal

$ telnet localhost 7000

Ausführen. Geben Sie ein Zeichen wie "hoge" ein. Wenn dieselbe Zeichenfolge angezeigt wird, ist dies in Ordnung.

Beispiel für eine Ausführungsbestätigung

$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hoge
hoge

Wenn Sie über die Befehlszeile erstellen möchten

$ swiftc main.swift -import-objc-header ../EchoServer-Bridging-Header.h -I/usr/local/include -L/usr/local/lib -luv

In diesem Fall befinden sich mehrere Hauptdateien im selben Verzeichnis, sodass Sie sie ausführen können.

Verwenden Sie Closure anstelle der globalen Funktion

Befehlszeilentool mit Swift2 - Cookpad-Entwicklerblog, wie im Abschnitt "Anschließen des Signals", dem Abschluss, beschrieben Kann als Funktionszeiger übergeben werden. Wir haben eine Implementierung von https://github.com/yokochie/EchoServer-Sample/blob/use_closure/EchoServer/main.swift anstelle eines Abschlusses vorbereitet.

Ich denke nicht, dass sich daran viel ändern wird, aber dem normalen Schließungstyp geht "@convention (c)" voraus. (Im Folgenden ein Beispiel)

let alloc_buffer: @convention(c) (UnsafeMutablePointer<uv_handle_t>, size_t, UnsafeMutablePointer<uv_buf_t>) -> Void = { (handle, suggested_size, buf) in
    buf.memory.base = UnsafeMutablePointer<CChar>.alloc(suggested_size)
    buf.memory.len = suggested_size
}

Am Ende (Eindruck)

Zum ersten Mal berührte ich die C-Sprachbibliothek von Swift und war überrascht, dass sie einfacher zu handhaben war als erwartet. Beim Vergleich des Quellcodes gibt es Unterschiede in der Definition von Variablen und Funktionen, aber ich denke, sie sind sehr ähnlich.

Ich denke, dass Swift als Implementierungssprache für iOS-Anwendungen Aufmerksamkeit erregt, aber ich denke, dass es interessanter wird, wenn Serverprogramme usw. in Swift implementiert werden.

Dieser Artikel ist zu einer Sammlung von Artikeln verschiedener Personen geworden, aber ich hoffe, dass mehr Menschen das Gleiche versuchen werden.

Verweise

Recommended Posts

Einführung in Swift / C Bridge mit der Geschichte der Portierung von Echo Server mit libuv
Erste Schritte mit Swift
Erste Schritte mit dem Language Server Protocol mit LSP4J
Erste Schritte mit Java-Programmen mit Visual Studio Code
Erste Schritte mit DBUnit
Verwenden Sie die C-Bibliothek mit Swift unter Verwendung von Clang-Modulen (Modulkarte).
Erste Schritte mit Ruby
Erste Schritte mit Doma-Transaktionen
Erste Schritte mit der Verarbeitung von Doma-Annotationen
Erste Schritte mit Java Collection
Erste Schritte mit JSP & Servlet
Erste Schritte mit Java Basics
Erste Schritte mit Spring Boot
Erste Schritte mit Ruby-Modulen
Erste Schritte mit Java_Kapitel 5_Praktische Übungen 5_4
[Google Cloud] Erste Schritte mit Docker
Erste Schritte mit Docker mit VS-Code