Je savais que je pourrais travailler avec des bibliothèques de langage C directement à partir de Swift, mais je ne l'avais jamais fait auparavant, c'est donc un tutoriel pour libuv uvbook tcp-echo-server Je voudrais porter) sur Swift pour commencer avec le pont en langage C.
Cette fois, j'utiliserai Xcode sur Mac pour porter tcp-echo-server. Le code source est ici https://github.com/yokochie/EchoServer-Sample
La version Xcode sera 7.2 et la version Swift sera 2.1.1.
libuv est requis pour porter le serveur tcp-echo-server de libuv. L'installation est facile avec Homebrew.
$ brew install --HEAD libuv
Une fois installés, les fichiers requis seront dans / 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
Créez un projet d'outil de ligne de commande en vous référant à l'article Création d'un moniteur de paquets avec Swift et Libpcap | Developers.IO.
Pour utiliser libuv, ajoutez d'abord libuv.dylib à partir des paramètres du projet et ajoutez / usr / local / include /, / usr / local / lib au chemin de recherche d'en-tête et au chemin de recherche de la bibliothèque dans le chemin de recherche.
Créez en quelque sorte Bridging-Header.h (facile de créer un nouveau fichier Objective-C et de le supprimer),
#include <uv.h>
Ajouter.
Ensuite, la méthode libuv sera suggérée comme indiqué dans la figure ci-dessous.
https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift Osez l'implémentation en langage C (https://github.com/nikhilm/uvbook/blob/master/code/tcp -J'ai posté quelque chose de similaire à (echo-server / main.c). Comme le montre la figure à la fin de la construction de l'environnement, la fonction peut être appelée telle quelle, donc si les types de variables sont correctement mis en correspondance, elle peut être facilement portée. Je pense que ce sera plus facile à comprendre si vous les comparez en lisant cet article.
[Utilisation de Swift avec Cocoa et Objective-C (Swift 2.1): Interagir avec les API C](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithCAPIs.html#//apple_ref/ Il est converti en un type commençant par l'acronyme C, tel que "CChar", "CInt", comme décrit dans doc / uid / TP40014216-CH8-ID17). (Cependant, le type suggéré sur XCode est un type avec un nombre explicite de bits, tel que ʻInt8 ou ʻInt32
.)
De plus, pour les pointeurs, Type *
devient ʻUnsafeMutablePointer et
const Type * devient ʻUnsafePointer <Type>
. De plus, «NULL» devient «nil».
Basé sur la conversion de type normal et la conversion de type de pointeur
int * hoge = NULL
Mais
var hoge: UnsafeMutablePointer<CInt> = nil
Sera.
La structure C peut être utilisée telle quelle comme structure Swift, mais si c'est une fonction qui nécessite un pointeur vers une variable Est OK si vous le préfixez avec &
(comme si vous aviez préfixé la définition de méthode avec inout). Le code source pour cette heure est main.swift: 66.
uv_ip4_addr("0.0.0.0", CInt(DEFAULT_PORT), &addr)
Cependant, cette technique ne semble pas fonctionner si des lancers se produisent. https://github.com/nikhilm/uvbook/blob/master/code/tcp-echo-server/main.c#L64
uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
Dans l'état actuel des choses, l'ajout de &
et le portage ne correspondaient pas au type et entraînait une erreur de compilation.
Par conséquent, [fonction withUnsafePointer
](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_StandardLibrary_Functions/index.html#//apple_ref/swift/func/s:FSs17withUnsterqPointerVFUF_s: FSs17withUnsterqPointerVSFUF0s17withUnsterq Je caste en utilisant le ʻinitializer.
withUnsafePointer(&addr) {
uv_tcp_bind(&server, UnsafePointer<sockaddr>($0), 0)
}
(UnsafePointer Structure Reference n'a rien qui puisse prendre directement le type de la variable à l'intérieur du pointeur. S'il vous plaît soyez prudente)
De plus, bien que libuv utilise beaucoup les fonctions de rappel, il était possible de spécifier les fonctions déclarées globalement telles quelles.
Par exemple, la fonction ʻuv_listenprend
void (* uv_connection_cb) (uv_stream_t * server, int status)à la fin de l'argument. Https://github.com/yokochie/EchoServer-Sample/blob/master/EchoServer/main.swift#L73 implémenté dans Swift accepte
func on_new_connect (server: UnsafeMutablePointer <uv_stream_t>, status: CInt)` tel quel Je peux le passer.
En C, vous pouvez utiliser les opérateurs *
et ->
pour référencer des variables dans des pointeurs, mais dans Swift vous utilisez la propriété memory
(https://github.com/yokochie/EchoServer). -Utilisé dans Sample / blob / master / EchoServer / main.swift # L13)
Utilisez la méthode ʻUnsafeMutablePointer pour allouer de la mémoire et la méthode
destory` pour la libérer.
Il semble que la bibliothèque standard Swift n'ait pas de fonction à générer vers la sortie d'erreur standard, donc cette fois, j'émets une déclaration d'erreur vers la sortie standard. Il semble que vous puissiez le faire en ouvrant OutputStream comme décrit dans http://ericasadun.com/2015/06/09/swift-2-0-how-to-print/.
Appuyez sur ⌘R sur Xcode pour exécuter. Puis dans le terminal
$ telnet localhost 7000
Éxécuter. Entrez un caractère tel que «hoge», et si la même chaîne de caractères est affichée, c'est OK.
Exemple de confirmation d'exécution
$ telnet localhost 7000
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hoge
hoge
Si vous souhaitez construire à partir de la ligne de commande
$ swiftc main.swift -import-objc-header ../EchoServer-Bridging-Header.h -I/usr/local/include -L/usr/local/lib -luv
Si vous le faites, vous aurez plus de fichiers main
dans le même répertoire, vous pourrez donc l'exécuter.
Outil de ligne de commande réalisé avec Swift2 - Blog des développeurs de Cookpad, comme décrit dans la section "Accrocher le signal", la fermeture Peut être passé en tant que pointeur de fonction. Nous avons préparé une implémentation de https://github.com/yokochie/EchoServer-Sample/blob/use_closure/EchoServer/main.swift au lieu d'une fermeture.
Je ne pense pas que cela changera beaucoup, mais le type de fermeture normal est précédé de @convention (c)
. (Ci-après, un exemple)
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
}
Pour la première fois, j'ai touché à la bibliothèque de langage C de Swift, et j'ai été surpris qu'elle soit plus facile à gérer que prévu. En comparant le code source, il existe des différences dans la manière dont les variables et les fonctions sont définies, mais je pense qu'elles sont très similaires.
Je pense que Swift attire l'attention en tant que langage d'implémentation d'application iOS, mais je pense qu'il deviendra plus intéressant lorsque les programmes serveur, etc. seront implémentés dans Swift.
Cet article est devenu une collection d'articles de différentes personnes, mais j'espère que plus de gens essaieront la même chose.
Recommended Posts