Retour à l'accueil

Serveur TCP dans iOS sur sockets POSIX

L'article détaille l'implémentation d'un serveur TCP dans une app iOS utilisant l'API POSIX. Les frameworks réseau d'Apple, création de socket, analyse HTTP et service de fichiers sont décrits. Code fonctionnel complet avec gestion d'erreurs fourni.

Serveur TCP dans iOS : guide complet sur les sockets
Advertisement 728x90

# Serveur TCP dans une application iOS utilisant les sockets POSIX : De la théorie à la pratique

Dans le développement iOS, la pile réseau couvre tout, des requêtes HTTP de haut niveau aux sockets BSD de bas niveau. URLSession est idéal pour les opérations HTTP et WebSocket standard, le framework Network gère TCP/UDP avec TLS, et CFNetwork prend en charge les anciens protocoles comme FTP et Bonjour. L’API POSIX fournit un accès direct à la couche transport, tandis que SwiftNIO ajoute des capacités côté serveur en Swift.

Tous ces outils reposent sur des sockets. Pour des protocoles personnalisés (comme SMTP ou IMAP) ou une logique serveur, vous avez besoin d’un accès à la couche transport. Cet article vous guide pas à pas dans l’implémentation d’un serveur TCP utilisant l’API POSIX — dépendances minimales et contrôle total.

Sockets POSIX : Création et configuration

La classe TCPServer encapsule le socket, le port et le cycle de vie :

Google AdInline article slot
final class TCPServer {
    let port: UInt16

    init(port: UInt16 = 8081) {
        self.port = port
    }

    deinit {
        stop()
    }

    func start() throws { }
    func stop() { }
}

Les erreurs sont fortement typées :

enum SocketError: LocalizedError {
  case socketCreationFailed(errno: Int32)
  case bindFailed(errno: Int32)
  case listenFailed(errno: Int32)
  case writeFailed(errno: Int32)
  case writeTimeout

  var errorDescription: String? { /* ... */ }
}

Dans start() :

  • socket(AF_INET, SOCK_STREAM, 0) crée un socket TCP IPv4. Il retourne un descripteur ou -1 en cas d’erreur (vérifiez errno).
  • setsockopt avec SO_REUSEADDR=1 permet de relier l’adresse sans délais TIME_WAIT.
var reuseAddr: Int32 = 1
setsockopt(currentSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, socklen_t(MemoryLayout<Int32>.size))

Liaison, écoute et gestion des connexions

La structure d’adresse sockaddr_in est remplie pour INADDR_ANY (0.0.0.0) :

Google AdInline article slot
var addr = sockaddr_in()
addr.sin_family = sa_family_t(AF_INET)
addr.sin_port = in_port_t(port.bigEndian)
addr.sin_addr.s_addr = in_addr_t(0)

bind(currentSocket, sockaddr_cast(&addr), socklen_t(MemoryLayout<sockaddr_in>.size))

listen(currentSocket, 10) met en file d’attente jusqu’à 10 connexions en attente.

La boucle de gestion s’exécute dans un thread en arrière-plan :

DispatchQueue.global().async { [weak self] in
    while let server = self, server.isRunning {
        var clientAddr = sockaddr_in()
        var len = socklen_t(MemoryLayout<sockaddr_in>.size)
        
        let clientSocket = accept(server.currentSocket, sockaddr_cast(&clientAddr), &len)
        // Handle clientSocket
    }
}

Analyse HTTP et service de fichiers

Le serveur implémente HTTP/1.1 de base. L’analyseur extrait la méthode, le chemin et les en-têtes de la requête brute.

Google AdInline article slot
struct HTTPRequest {
    let method: String
    let path: String
    let headers: [String: String]
    let body: Data?
}

Pour GET /files/, il retourne une liste de fichiers du répertoire Documents :

<html><body><h1>App Files</h1><ul>
<li><a href="/file/filename">filename</a></li>
</ul></body></html>

Les téléchargements via /file/ : utilise sendfile pour l’efficacité.

La réponse est construite manuellement :

"HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/html\r\n"
+ "Content-Length: \(data.count)\r\n"
+ "\r\n" + String(data: data, encoding: .utf8)!

Sécurité et limitations

  • Réseau local : Le serveur se lie à 0.0.0.0:8081, accessible via l’IP de l’appareil.
  • Sandbox : Accès limité à Documents. Pas de fichiers système.
  • Timeout : 30 s par requête ; fermer en cas d’erreurs.
  • Limitations iOS : Le réseau en arrière-plan nécessite background-fetch ou des entitlements VoIP.

Points clés :

  • L’API POSIX est une interface de bas niveau universelle, identique à macOS/Linux.
  • SO_REUSEADDR est essentiel pour les redémarrages rapides en développement.
  • Exécutez accept() dans une boucle asynchrone sans bloquer le thread principal.
  • L’analyse HTTP est minimaliste : méthode + chemin + Content-Length.
  • sendfile() surpasse write() pour les gros fichiers.

Tests et débogage

  • Lancement : try server.start()
  • Accès local : http://localhost:8081/files
  • Accès réseau : http://192.168.1.100:8081/files
  • Journaux : print(String(cString: strerror(errno)))
  • Instruments : Utilisez Network Link Conditioner pour les simulations.

Le projet démontre le cycle complet : du socket à l’interface web. Le code est extensible pour WebSocket ou protocoles personnalisés.

— Editorial Team

Advertisement 728x90

Lire ensuite