Exemplos de Rede macOS Swift

Exemplos de rede macOS Swift incluindo requisições HTTP, servidor HTTP e programação de sockets TCP

💻 Requisição HTTP swift

🟡 intermediate ⭐⭐⭐

Enviar requisições GET e POST usando URLSession com tratamento de erro adequado e processamento de resposta

⏱️ 25 min 🏷️ swift, macos, networking, http
Prerequisites: Basic Swift knowledge, Foundation framework, Networking concepts
// macOS Swift HTTP Request Examples
// Using Foundation framework

import Foundation

// 1. Simple GET Request
class SimpleGETRequest {

    static func fetch(url: String) {
        print("\n--- Simple GET Request ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            guard let httpResponse = response as? HTTPURLResponse else {
                print("Invalid response")
                return
            }

            print("Status Code: \(httpResponse.statusCode)")

            if let data = data, let content = String(data: data, encoding: .utf8) {
                print("Response (first 200 chars): \(String(content.prefix(200)))")
            }
        }

        task.resume()
    }
}

// 2. GET Request with Parameters
class GETWithParameters {

    static func fetchWithParams(baseUrl: String, params: [String: String]) {
        print("\n--- GET with Parameters ---")

        guard var urlComponents = URLComponents(string: baseUrl) else {
            print("Invalid URL")
            return
        }

        urlComponents.queryItems = params.map { key, value in
            URLQueryItem(name: key, value: value)
        }

        guard let url = urlComponents.url else {
            print("Invalid URL with parameters")
            return
        }

        print("Request URL: \(url.absoluteString)")

        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            if let httpResponse = response as? HTTPURLResponse {
                print("Status Code: \(httpResponse.statusCode)")
            }
        }

        task.resume()
    }
}

// 3. POST Request with JSON Body
class POSTRequest {

    static func postJSON(url: String, body: [String: Any]) {
        print("\n--- POST JSON Request ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        do {
            let jsonData = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted)
            request.httpBody = jsonData

            if let jsonString = String(data: jsonData, encoding: .utf8) {
                print("Request Body: \(jsonString)")
            }

            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                if let error = error {
                    print("Error: \(error.localizedDescription)")
                    return
                }

                if let httpResponse = response as? HTTPURLResponse {
                    print("Status Code: \(httpResponse.statusCode)")
                }

                if let data = data, let responseString = String(data: data, encoding: .utf8) {
                    print("Response: \(responseString)")
                }
            }

            task.resume()

        } catch {
            print("JSON serialization error: \(error)")
        }
    }
}

// 4. POST Request with Form Data
class POSTFormData {

    static func postForm(url: String, params: [String: String]) {
        print("\n--- POST Form Data ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        var request = URLRequest(url: url)
        request.httpMethod = "POST"

        let formString = params.map { key, value in
            "\(key)=\(value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? value)"
        }.joined(separator: "&")

        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpBody = formString.data(using: .utf8)

        print("Form Data: \(formString)")

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            if let httpResponse = response as? HTTPURLResponse {
                print("Status Code: \(httpResponse.statusCode)")
            }
        }

        task.resume()
    }
}

// 5. Request with Custom Headers
class RequestWithHeaders {

    static func fetchWithHeaders(url: String, headers: [String: String]) {
        print("\n--- Request with Custom Headers ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        var request = URLRequest(url: url)

        for (key, value) in headers {
            request.setValue(value, forHTTPHeaderField: key)
            print("\(key): \(value)")
        }

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            if let httpResponse = response as? HTTPURLResponse {
                print("Status Code: \(httpResponse.statusCode)")
                print("Response Headers:")
                if let allHeaders = httpResponse.allHeaderFields as? [String: String] {
                    for (key, value) in allHeaders {
                        print("  \(key): \(value)")
                    }
                }
            }
        }

        task.resume()
    }
}

// 6. Download File
class DownloadFile {

    static func downloadFile(url: String, destination: String) {
        print("\n--- Download File ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        let task = URLSession.shared.downloadTask(with: url) { tempURL, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            guard let tempURL = tempURL else {
                print("Invalid temp URL")
                return
            }

            do {
                let fileManager = FileManager.default
                let destURL = URL(fileURLWithPath: destination)

                // Create directory if needed
                let destDir = destURL.deletingLastPathComponent()
                if !fileManager.fileExists(atPath: destDir.path) {
                    try fileManager.createDirectory(atPath: destDir.path, withIntermediateDirectories: true)
                }

                // Remove existing file
                if fileManager.fileExists(atPath: destination) {
                    try fileManager.removeItem(atPath: destination)
                }

                // Move file
                try fileManager.moveItem(at: tempURL, to: destURL)

                let attributes = try fileManager.attributesOfItem(atPath: destination)
                if let fileSize = attributes[.size] as? UInt64 {
                    print("Downloaded: \(destination)")
                    print("File size: \(fileSize) bytes")
                }

            } catch {
                print("File save error: \(error)")
            }
        }

        task.resume()
    }
}

// 7. Upload File with Progress
class UploadFile {

    static func uploadFile(url: String, filePath: String) {
        print("\n--- Upload File ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)) else {
            print("Cannot read file")
            return
        }

        var request = URLRequest(url: url)
        request.httpMethod = "POST"

        let boundary = "Boundary-\(UUID().uuidString)"
        request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

        var body = Data()

        // Add file data
        body.append("--\(boundary)\r\n".data(using: .utf8)!)
        body.append("Content-Disposition: form-data; name=\"file\"; filename=\"\((filePath as NSString).lastPathComponent)\"\r\n".data(using: .utf8)!)
        body.append("Content-Type: application/octet-stream\r\n\r\n".data(using: .utf8)!)
        body.append(fileData)
        body.append("\r\n".data(using: .utf8)!)
        body.append("--\(boundary)--\r\n".data(using: .utf8)!)

        request.httpBody = body

        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            if let httpResponse = response as? HTTPURLResponse {
                print("Status Code: \(httpResponse.statusCode)")
            }

            print("Upload completed")
        }

        task.resume()
    }
}

// 8. Request with Timeout
class RequestWithTimeout {

    static func fetchWithTimeout(url: String, timeout: TimeInterval) {
        print("\n--- Request with Timeout ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = timeout

        let session = URLSession(configuration: configuration)

        let task = session.dataTask(with: url) { data, response, error in
            if let error = error {
                print("Error: \(error.localizedDescription)")
                return
            }

            if let httpResponse = response as? HTTPURLResponse {
                print("Status Code: \(httpResponse.statusCode)")
            }
        }

        task.resume()
    }
}

// 9. Async/Await HTTP Request (Swift 5.5+)
@available(macOS 12.0, *)
class ModernHTTPRequest {

    static func fetchAsync(url: String) async {
        print("\n--- Async/Await Request ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        do {
            let (data, response) = try await URLSession.shared.data(from: url)

            if let httpResponse = response as? HTTPURLResponse {
                print("Status Code: \(httpResponse.statusCode)")
            }

            if let content = String(data: data, encoding: .utf8) {
                print("Response (first 200 chars): \(String(content.prefix(200)))")
            }

        } catch {
            print("Error: \(error.localizedDescription)")
        }
    }
}

// 10. Request with Response Decoding
struct User: Codable {
    let id: Int
    let name: String
    let email: String
}

class RequestWithDecoding {

    static func fetchAndDecode<T: Decodable>(url: String, type: T.Type) {
        print("\n--- Request with Decoding ---")

        guard let url = URL(string: url) else {
            print("Invalid URL")
            return
        }

        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data else {
                if let error = error {
                    print("Error: \(error.localizedDescription)")
                }
                return
            }

            do {
                let decoder = JSONDecoder()
                let result = try decoder.decode(type, from: data)
                print("Decoded result: \(result)")
            } catch {
                print("Decoding error: \(error)")
            }
        }

        task.resume()
    }
}

// Main demonstration
func demonstrateHTTPRequests() {
    print("=== macOS Swift HTTP Request Examples ===")

    // Note: Using example.com for demonstration
    // In real usage, replace with actual API endpoints

    // 1. Simple GET
    SimpleGETRequest.fetch(url: "https://example.com")
    Thread.sleep(forTimeInterval: 1)

    // 2. GET with parameters
    GETWithParameters.fetchWithParams(
        baseUrl: "https://httpbin.org/get",
        params: ["param1": "value1", "param2": "value2"]
    )
    Thread.sleep(forTimeInterval: 1)

    // 3. POST JSON
    POSTRequest.postJSON(
        url: "https://httpbin.org/post",
        body: ["name": "John Doe", "email": "[email protected]", "age": 30]
    )
    Thread.sleep(forTimeInterval: 1)

    // 4. POST Form Data
    POSTFormData.postForm(
        url: "https://httpbin.org/post",
        params: ["username": "testuser", "password": "testpass"]
    )
    Thread.sleep(forTimeInterval: 1)

    // 5. Custom Headers
    RequestWithHeaders.fetchWithHeaders(
        url: "https://httpbin.org/headers",
        headers: [
            "User-Agent": "SwiftNetworking/1.0",
            "Accept": "application/json",
            "Authorization": "Bearer token123"
        ]
    )
    Thread.sleep(forTimeInterval: 1)

    // 6. Download File
    DownloadFile.downloadFile(
        url: "https://example.com",
        destination: "/tmp/downloaded_file.html"
    )
    Thread.sleep(forTimeInterval: 1)

    // 7. Request with Timeout
    RequestWithTimeout.fetchWithTimeout(url: "https://example.com", timeout: 5)
    Thread.sleep(forTimeInterval: 1)

    // 8. Async Request (if available)
    if #available(macOS 12.0, *) {
        Task {
            await ModernHTTPRequest.fetchAsync(url: "https://example.com")
        }
        Thread.sleep(forTimeInterval: 1)
    }

    // 9. Request with Decoding
    RequestWithDecoding.fetchAndDecode(
        url: "https://jsonplaceholder.typicode.com/users/1",
        type: User.self
    )
    Thread.sleep(forTimeInterval: 2)

    print("\n=== All HTTP Request Examples Completed ===")
}

// Run demonstration
demonstrateHTTPRequests()

💻 Socket TCP swift

🟡 intermediate ⭐⭐⭐⭐

Criar sockets de cliente e servidor TCP para comunicação bidirecional

⏱️ 40 min 🏷️ swift, macos, networking, tcp
Prerequisites: Intermediate Swift, Socket programming, Networking concepts
// macOS Swift TCP Socket Examples
// Using Foundation and Network framework

import Foundation

// 1. TCP Server
class TCPServer {

    private var serverSocket: Int32 = -1
    private var isRunning = false
    private var clientHandlers: [Thread] = []

    func start(port: UInt16) {
        print("\n--- Starting TCP Server on port \(port) ---")

        // Create socket
        serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
        guard serverSocket != -1 else {
            print("Failed to create socket")
            return
        }

        // Set socket options
        var yes: Int32 = 1
        setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &yes, socklen_t(MemoryLayout<Int32>.size))

        // Bind to address
        var address = sockaddr_in()
        address.sin_family = sa_family_t(AF_INET)
        address.sin_port = port.bigEndian
        address.sin_addr.s_addr = INADDR_ANY

        let bindResult = withUnsafePointer(to: &address) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                bind(serverSocket, $0, socklen_t(MemoryLayout<sockaddr_in>.size))
            }
        }

        guard bindResult == 0 else {
            print("Failed to bind to port: \(errno)")
            close(serverSocket)
            return
        }

        // Listen
        guard listen(serverSocket, 5) == 0 else {
            print("Failed to listen")
            close(serverSocket)
            return
        }

        isRunning = true
        print("Server listening on port \(port)")

        // Accept connections
        DispatchQueue.global(qos: .background).async { [weak self] in
            self?.acceptConnections()
        }
    }

    private func acceptConnections() {
        while isRunning {
            var clientAddress = sockaddr_in()
            var addressLength = socklen_t(MemoryLayout<sockaddr_in>.size)

            let clientSocket = withUnsafeMutablePointer(to: &clientAddress) {
                $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                    accept(serverSocket, $0, &addressLength)
                }
            }

            guard clientSocket != -1 else {
                continue
            }

            // Get client info
            let clientIP = getIPAddress(from: &clientAddress)
            print("Client connected from \(clientIP)")

            // Handle client
            handleClient(socket: clientSocket)
        }
    }

    private func handleClient(socket: Int32) {
        DispatchQueue.global(qos: .background).async {
            var buffer = [UInt8](repeating: 0, count: 1024)

            while true {
                let bytesRead = read(socket, &buffer, buffer.count)

                if bytesRead <= 0 {
                    close(socket)
                    print("Client disconnected")
                    return
                }

                if let message = String(bytes: buffer.prefix(bytesRead), encoding: .utf8) {
                    print("Received: \(message)")

                    // Echo back
                    let response = "Echo: \(message)"
                    response.withCString { ptr in
                        write(socket, ptr, response.count)
                    }
                }
            }
        }
    }

    private func getIPAddress(from address: inout sockaddr_in) -> String {
        var ipAddress = [CChar](repeating: 0, count: Int(INET_ADDRSTRLEN))
        withUnsafePointer(to: &address.sin_addr) {
            inet_ntop(AF_INET, $0, &ipAddress, socklen_t(INET_ADDRSTRLEN))
        }
        return String(cString: ipAddress)
    }

    func broadcast(_ message: String) {
        // Broadcast to all connected clients
        // Implementation depends on how you track clients
    }

    func stop() {
        isRunning = false
        if serverSocket != -1 {
            close(serverSocket)
        }
        print("Server stopped")
    }
}

// 2. TCP Client
class TCPClient {

    private var clientSocket: Int32 = -1

    func connect(host: String, port: UInt16) -> Bool {
        print("\n--- Connecting to \(host):\(port) ---")

        // Create socket
        clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
        guard clientSocket != -1 else {
            print("Failed to create socket")
            return false
        }

        // Resolve host
        var hints = addrinfo()
        hints.ai_family = AF_INET
        hints.ai_socktype = SOCK_STREAM

        var result: UnsafeMutablePointer<addrinfo>?
        let status = getaddrinfo(host, String(port), &hints, &result)

        guard status == 0, let info = result else {
            print("Failed to resolve host")
            close(clientSocket)
            return false
        }

        defer { freeaddrinfo(info) }

        // Connect
        guard connect(clientSocket, info.pointee.ai_addr, info.pointee.ai_addrlen) == 0 else {
            print("Failed to connect: \(errno)")
            close(clientSocket)
            return false
        }

        print("Connected to server")
        return true
    }

    func send(_ message: String) -> Bool {
        guard clientSocket != -1 else {
            print("Not connected")
            return false
        }

        let bytesSent = message.withCString { ptr in
            write(clientSocket, ptr, message.count)
        }

        if bytesSent > 0 {
            print("Sent: \(message)")
            return true
        }

        print("Failed to send")
        return false
    }

    func receive() -> String? {
        guard clientSocket != -1 else {
            return nil
        }

        var buffer = [UInt8](repeating: 0, count: 1024)
        let bytesRead = read(clientSocket, &buffer, buffer.count)

        guard bytesRead > 0 else {
            return nil
        }

        return String(bytes: buffer.prefix(bytesRead), encoding: .utf8)
    }

    func disconnect() {
        if clientSocket != -1 {
            close(clientSocket)
            clientSocket = -1
        }
        print("Disconnected")
    }
}

// 3. Chat Server
class ChatServer {

    private var server = TCPServer()
    private var clients: [Int32] = []
    private let clientsLock = NSLock()

    func start(port: UInt16) {
        print("\n--- Starting Chat Server on port \(port) ---")

        // Start TCP server
        server.start(port: port)

        print("Chat server running. Connect clients to chat!")
    }

    func broadcast(_ message: String, from socket: Int32) {
        clientsLock.lock()
        let clientList = clients
        clientsLock.unlock()

        for client in clientList {
            if client != socket {
                message.withCString { ptr in
                    write(client, ptr, message.count)
                }
            }
        }
    }

    func addClient(_ socket: Int32) {
        clientsLock.lock()
        clients.append(socket)
        clientsLock.unlock()

        broadcast("User joined", from: socket)
    }

    func removeClient(_ socket: Int32) {
        clientsLock.lock()
        clients.removeAll { $0 == socket }
        clientsLock.unlock()

        close(socket)
    }
}

// 4. TCP Client with Reconnect
class TCPClientWithReconnect {

    private var client = TCPClient()
    private var isConnected = false
    private var reconnectAttempts = 0
    private let maxAttempts = 5

    func connect(host: String, port: UInt16) {
        while reconnectAttempts < maxAttempts && !isConnected {
            if client.connect(host: host, port: port) {
                isConnected = true
                reconnectAttempts = 0
                return
            }

            reconnectAttempts += 1
            print("Reconnect attempt \(reconnectAttempts) in 2 seconds...")
            Thread.sleep(forTimeInterval: 2)
        }

        print("Failed to connect after \(maxAttempts) attempts")
    }

    func sendWithRetry(_ message: String) -> Bool {
        if isConnected {
            return client.send(message)
        } else {
            print("Not connected, attempting to reconnect...")
            return false
        }
    }

    func disconnect() {
        isConnected = false
        client.disconnect()
    }
}

// 5. Non-blocking Socket
class NonBlockingSocket {

    private var socket: Int32 = -1

    func connect(host: String, port: UInt16) {
        socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
        guard socket != -1 else { return }

        // Set non-blocking
        var flags = fcntl(socket, F_GETFL, 0)
        fcntl(socket, F_SETFL, flags | O_NONBLOCK)

        // Connect (non-blocking)
        var address = sockaddr_in()
        address.sin_family = sa_family_t(AF_INET)
        address.sin_port = port.bigEndian

        let result = connect(socket, nil, 0)
        if result == -1 && errno != EINPROGRESS {
            print("Connection error")
            close(socket)
            return
        }

        print("Non-blocking connection initiated")
    }

    func sendNonBlocking(_ data: Data) {
        var buffer = [UInt8](data)
        let sent = write(socket, &buffer, buffer.count)
        print("Sent \(sent) bytes")
    }

    func receiveNonBlocking() -> Data? {
        var buffer = [UInt8](repeating: 0, count: 1024)
        let received = read(socket, &buffer, buffer.count)

        if received > 0 {
            return Data(bytes: buffer, count: received)
        }

        return nil
    }
}

// 6. Socket with Timeout
class SocketWithTimeout {

    private var socket: Int32 = -1

    func connectWithTimeout(host: String, port: UInt16, timeout: TimeInterval) -> Bool {
        socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
        guard socket != -1 else { return false }

        // Set timeout
        var tv = timeval(tv_sec: Int(timeout), tv_usec: 0)
        setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &tv, socklen_t(MemoryLayout<timeval>.size))
        setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &tv, socklen_t(MemoryLayout<timeval>.size))

        // Connect and read with timeout
        // ... connection logic ...

        return true
    }
}

// 7. Data Stream over TCP
class TCPDataStream {

    private var client = TCPClient()

    func sendStream(host: String, port: UInt16, data: [Data]) {
        guard client.connect(host: host, port: port) else {
            return
        }

        defer { client.disconnect() }

        for (index, chunk) in data.enumerated() {
            // Send header with chunk size
            let header = "\(chunk.count);"
            _ = header.withCString { ptr in
                write(client.clientSocket, ptr, header.count)
            }

            // Send data
            chunk.withUnsafeBytes { ptr in
                write(client.clientSocket, ptr.baseAddress, chunk.count)
            }

            print("Sent chunk \(index + 1)/\(data.count): \(chunk.count) bytes")
            Thread.sleep(forTimeInterval: 0.1)
        }

        // Send end marker
        let endMarker = "0;"
        _ = endMarker.withCString { ptr in
            write(client.clientSocket, ptr, endMarker.count)
        }

        print("Stream completed")
    }

    func receiveStream() -> [Data] {
        var receivedData: [Data] = []
        var buffer = [UInt8](repeating: 0, count: 1024)

        while true {
            // Read chunk size
            var sizeBuffer = [UInt8]()
            while true {
                let count = read(client.clientSocket, &buffer, 1)
                guard count > 0 else { return receivedData }

                if buffer[0] == UInt8(ascii: ";") {
                    break
                }
                sizeBuffer.append(buffer[0])
            }

            guard let sizeString = String(bytes: sizeBuffer, encoding: .utf8),
                  let size = Int(sizeString) else {
                continue
            }

            if size == 0 {
                print("End of stream")
                break
            }

            // Read data
            var chunk = [UInt8](repeating: 0, count: size)
            var totalReceived = 0

            while totalReceived < size {
                let count = read(client.clientSocket, &chunk[totalReceived], size - totalReceived)
                guard count > 0 else { break }
                totalReceived += count
            }

            receivedData.append(Data(chunk))
            print("Received chunk: \(totalReceived) bytes")
        }

        return receivedData
    }
}

// 8. Protocol Buffer over TCP
class ProtocolBufferSocket {

    func sendProtobufMessage<T: Encodable>(_ message: T, socket: Int32) {
        // Encode message
        // Send length prefix followed by message data
        // Implementation depends on protobuf library
    }
}

// 9. Heartbeat Connection
class HeartbeatConnection {

    private var client = TCPClient()
    private var heartbeatTimer: Timer?
    private var isRunning = false

    func connectWithHeartbeat(host: String, port: UInt16, interval: TimeInterval = 5) {
        guard client.connect(host: host, port: port) else {
            return
        }

        isRunning = true

        // Start heartbeat
        heartbeatTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { [weak self] _ in
            self?.sendHeartbeat()
        }

        // Listen for responses
        DispatchQueue.global(qos: .background).async { [weak self] in
            self?.listen()
        }
    }

    private func sendHeartbeat() {
        guard isRunning else { return }
        _ = client.send("HEARTBEAT")
    }

    private func listen() {
        while isRunning {
            if let response = client.receive() {
                print("Received: \(response)")
            }
            Thread.sleep(forTimeInterval: 0.1)
        }
    }

    func disconnect() {
        isRunning = false
        heartbeatTimer?.invalidate()
        client.disconnect()
    }
}

// Main demonstration
func demonstrateTCPSockets() {
    print("=== macOS Swift TCP Socket Examples ===")

    // 1. Start server in background
    let serverThread = Thread {
        let server = TCPServer()
        server.start(port: 9999)

        // Keep running
        RunLoop.current.run()
    }
    serverThread.start()

    Thread.sleep(forTimeInterval: 1)

    // 2. Connect client
    print("\n--- Client Connection ---")
    let client = TCPClient()

    if client.connect(host: "localhost", port: 9999) {
        // Send messages
        _ = client.send("Hello, Server!")
        Thread.sleep(forTimeInterval: 0.5)

        // Receive response
        if let response = client.receive() {
            print("Server response: \(response)")
        }

        // Send more messages
        _ = client.send("Message 2")
        Thread.sleep(forTimeInterval: 0.5)

        _ = client.send("Message 3")
        Thread.sleep(forTimeInterval: 0.5)

        client.disconnect()
    }

    Thread.sleep(forTimeInterval: 1)

    print("\n=== TCP Socket Examples Completed ===")
    print("Note: In production, implement proper signal handling for cleanup")
}

// Uncomment to run demonstration
// demonstrateTCPSockets()

print("\nNote: TCP socket examples provided. Uncomment demonstrateTCPSockets() to run.")

💻 Servidor HTTP swift

🔴 complex ⭐⭐⭐⭐⭐

Criar um servidor HTTP simples usando framework Vapor ou Swift nativo com sockets

⏱️ 45 min 🏷️ swift, macos, networking, server
Prerequisites: Advanced Swift, Networking, Socket programming
// macOS Swift HTTP Server Examples
// Using Foundation and Network framework

import Foundation

// 1. Simple HTTP Server using sockets
class SimpleHTTPServer {

    private var listenerSocket: Int32 = -1
    private var isRunning = false

    func start(port: UInt16) {
        print("\n--- Starting HTTP Server on port \(port) ---")

        // Create socket
        listenerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
        guard listenerSocket != -1 else {
            print("Failed to create socket")
            return
        }

        // Set socket options
        var yes: Int32 = 1
        setsockopt(listenerSocket, SOL_SOCKET, SO_REUSEADDR, &yes, socklen_t(MemoryLayout<Int32>.size))

        // Bind to port
        var addr = sockaddr_in()
        addr.sin_family = sa_family_t(AF_INET)
        addr.sin_port = port.bigEndian
        addr.sin_addr.s_addr = INADDR_ANY

        let bindResult = withUnsafePointer(to: &addr) {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                bind(listenerSocket, $0, socklen_t(MemoryLayout<sockaddr_in>.size))
            }
        }

        guard bindResult == 0 else {
            print("Failed to bind to port")
            close(listenerSocket)
            return
        }

        // Listen
        guard listen(listenerSocket, 5) == 0 else {
            print("Failed to listen")
            close(listenerSocket)
            return
        }

        isRunning = true
        print("Server started on http://localhost:\(port)")

        // Accept connections in background thread
        DispatchQueue.global(qos: .background).async { [weak self] in
            self?.acceptConnections()
        }
    }

    private func acceptConnections() {
        while isRunning {
            var clientAddr = sockaddr_in()
            var clientLen = socklen_t(MemoryLayout<sockaddr_in>.size)

            let clientSocket = withUnsafeMutablePointer(to: &clientAddr) {
                $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                    accept(listenerSocket, $0, &clientLen)
                }
            }

            guard clientSocket != -1 else {
                continue
            }

            // Handle client in background
            DispatchQueue.global(qos: .background).async { [weak self] in
                self?.handleClient(clientSocket: clientSocket)
            }
        }
    }

    private func handleClient(clientSocket: Int32) {
        defer { close(clientSocket) }

        // Read request
        var buffer = [UInt8](repeating: 0, count: 4096)
        let bytesRead = read(clientSocket, &buffer, buffer.count)

        guard bytesRead > 0 else {
            return
        }

        let request = String(bytes: buffer.prefix(bytesRead), encoding: .utf8) ?? ""
        print("\nRequest received:")
        print(request.prefix(500))

        // Parse request
        let lines = request.components(separatedBy: "\r\n")
        guard let requestLine = lines.first,
              let parts = requestLine.components(separatedBy: " ").split(separator: " ").map(String.init),
              parts.count >= 2,
              let method = parts.first,
              let path = parts.dropFirst().first else {
            sendResponse(clientSocket: clientSocket, statusCode: 400, body: "Bad Request")
            return
        }

        print("Method: \(method), Path: \(path)")

        // Handle different paths
        let response: String
        switch path {
        case "/":
            response = createHTMLResponse("<h1>Welcome to Swift HTTP Server</h1><p>This is a simple HTTP server built with Swift.</p>")
        case "/about":
            response = createHTMLResponse("<h1>About</h1><p>Swift HTTP Server v1.0</p>")
        case "/json":
            let json = "{\"message\": \"Hello from Swift\", \"status\": \"success\"}"
            response = createJSONResponse(json)
        case "/time":
            let time = Date().description
            response = createJSONResponse("{\"time\": \"\(time)\"}")
        default:
            response = createHTMLResponse("<h1>404 Not Found</h1><p>The page \(path) was not found.</p>", statusCode: 404)
        }

        // Send response
        _ = write(clientSocket, response, response.count)
        print("Response sent")
    }

    private func createHTMLResponse(_ body: String, statusCode: Int = 200) -> String {
        let statusText: String
        switch statusCode {
        case 200: statusText = "OK"
        case 404: statusText = "Not Found"
        default: statusText = "OK"
        }

        let html = """
        <!DOCTYPE html>
        <html>
        <head>
            <title>Swift Server</title>
            <style>
                body { font-family: Arial, sans-serif; margin: 40px; }
                h1 { color: #333; }
            </style>
        </head>
        <body>
            \(body)
        </body>
        </html>
        """

        return """
        HTTP/1.1 \(statusCode) \(statusText)\r
        Content-Type: text/html\r
        Content-Length: \(html.count)\r
        Connection: close\r
        \r
        \(html)
        """
    }

    private func createJSONResponse(_ json: String) -> String {
        return """
        HTTP/1.1 200 OK\r
        Content-Type: application/json\r
        Content-Length: \(json.count)\r
        Connection: close\r
        \r
        \(json)
        """
    }

    private func sendResponse(clientSocket: Int32, statusCode: Int, body: String) {
        let response = createHTMLResponse(body, statusCode: statusCode)
        _ = write(clientSocket, response, response.count)
    }

    func stop() {
        isRunning = false
        if listenerSocket != -1 {
            close(listenerSocket)
        }
        print("Server stopped")
    }
}

// 2. Request Handler
class RequestHandler {

    struct HTTPRequest {
        let method: String
        let path: String
        let headers: [String: String]
        let body: String
    }

    struct HTTPResponse {
        let statusCode: Int
        let headers: [String: String]
        let body: String
    }

    static func parseRequest(_ data: String) -> HTTPRequest? {
        let lines = data.components(separatedBy: "\r\n")
        guard let requestLine = lines.first,
              let parts = requestLine.components(separatedBy: " ").split(separator: " ").map(String.init),
              parts.count >= 2 else {
            return nil
        }

        let method = parts[0]
        let path = parts[1]

        var headers: [String: String] = [:]
        var headerEndIndex = 1

        for (index, line) in lines.dropFirst().enumerated() {
            if line.isEmpty {
                headerEndIndex = index + 2
                break
            }
            let headerParts = line.components(separatedBy: ": ")
            if headerParts.count == 2 {
                headers[headerParts[0]] = headerParts[1]
            }
        }

        let body = lines.dropFirst(headerEndIndex).joined(separator: "\r\n")

        return HTTPRequest(method: method, path: path, headers: headers, body: body)
    }

    static func routeRequest(_ request: HTTPRequest) -> HTTPResponse {
        switch request.method {
        case "GET":
            return handleGET(request)
        case "POST":
            return handlePOST(request)
        default:
            return HTTPResponse(statusCode: 405, headers: [:], body: "Method Not Allowed")
        }
    }

    private static func handleGET(_ request: HTTPRequest) -> HTTPResponse {
        switch request.path {
        case "/":
            return HTMLResponse("<h1>Welcome</h1><p>Use /json for JSON response</p>")
        case "/json":
            return JSONResponse(["message": "Hello", "status": "success"])
        case "/users":
            let users = [
                ["id": 1, "name": "John"],
                ["id": 2, "name": "Jane"]
            ]
            return JSONResponse(users)
        default:
            return HTMLResponse("<h1>404</h1>", statusCode: 404)
        }
    }

    private static func handlePOST(_ request: HTTPRequest) -> HTTPResponse {
        switch request.path {
        case "/echo":
            return JSONResponse(["echo": request.body])
        default:
            return HTMLResponse("<h1>POST received</h1>")
        }
    }

    private static func HTMLResponse(_ body: String, statusCode: Int = 200) -> HTTPResponse {
        return HTTPResponse(
            statusCode: statusCode,
            headers: ["Content-Type": "text/html"],
            body: body
        )
    }

    private static func JSONResponse(_ data: Any) -> HTTPResponse {
        guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []),
              let jsonString = String(data: jsonData, encoding: .utf8) else {
            return HTTPResponse(statusCode: 500, headers: [:], body: "Internal Server Error")
        }

        return HTTPResponse(
            statusCode: 200,
            headers: ["Content-Type": "application/json"],
            body: jsonString
        )
    }
}

// 3. Router with Middleware
class Router {

    typealias Middleware = (URLRequest) -> URLRequest?
    typealias Handler = (URLRequest) -> String

    struct Route {
        let method: String
        let path: String
        let handler: Handler
    }

    private var routes: [Route] = []
    private var middlewares: [Middleware] = []

    func addMiddleware(_ middleware: @escaping Middleware) {
        middlewares.append(middleware)
    }

    func addRoute(method: String, path: String, handler: @escaping Handler) {
        routes.append(Route(method: method, path: path, handler: handler))
    }

    func handle(method: String, path: String, headers: [String: String], body: String) -> (Int, [String: String], String)? {
        // Apply middlewares
        for middleware in middlewares {
            // Middleware processing (simplified)
        }

        // Find matching route
        for route in routes {
            if route.method == method && route.path == path {
                let responseBody = route.handler(
                    URLRequest(url: URL(string: "http://localhost\(path)")!)
                )
                return (200, ["Content-Type": "text/html"], responseBody)
            }
        }

        // No matching route
        return (404, [:], "<h1>404 Not Found</h1>")
    }
}

// 4. Static File Server
class StaticFileServer {

    func serve(file: String, from documentRoot: String) -> (Int, [String: String], String)? {
        let filePath = documentRoot + file

        guard FileManager.default.fileExists(atPath: filePath) else {
            return nil
        }

        guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
              let content = String(data: fileData, encoding: .utf8) else {
            return (500, [:], "Internal Server Error")
        }

        let ext = (filePath as NSString).pathExtension
        let contentType = getContentType(for: ext)

        return (200, ["Content-Type": contentType], content)
    }

    private func getContentType(for extension: String) -> String {
        switch `extension`.lowercased() {
        case "html": return "text/html"
        case "css": return "text/css"
        case "js": return "application/javascript"
        case "json": return "application/json"
        case "png": return "image/png"
        case "jpg", "jpeg": return "image/jpeg"
        case "gif": return "image/gif"
        default: return "text/plain"
        }
    }
}

// 5. Server with Logging
class ServerWithLogging {

    private var server: SimpleHTTPServer

    init() {
        server = SimpleHTTPServer()
    }

    func start(port: UInt16) {
        print("Starting server with logging...")
        server.start(port: port)
    }

    private func logRequest(_ method: String, _ path: String, _ statusCode: Int) {
        let timestamp = Date()
        print("[\(timestamp)] \(method) \(path) - \(statusCode)")
    }
}

// 6. REST API Server Example
class RESTAPIServer {

    private var data: [String: Any] = [
        "users": [
            ["id": 1, "name": "John Doe", "email": "[email protected]"],
            ["id": 2, "name": "Jane Smith", "email": "[email protected]"]
        ]
    ]

    func handleRequest(method: String, path: String, body: String?) -> (Int, String)? {
        let pathComponents = path.components(separatedBy: "/").filter { !$0.isEmpty }

        guard pathComponents.count >= 2 else {
            return (400, "Invalid path")
        }

        let resource = pathComponents[1]

        switch (method, resource) {
        case ("GET", "users"):
            return handleGetUsers()
        case ("GET", "users"):
            if pathComponents.count == 3,
               let id = Int(pathComponents[2]) {
                return handleGetUser(id: id)
            }
            return (400, "Invalid user ID")
        case ("POST", "users"):
            return handleCreateUser(body: body)
        default:
            return (404, "Not Found")
        }
    }

    private func handleGetUsers() -> (Int, String) {
        if let users = data["users"] as? [[String: Any]],
           let jsonData = try? JSONSerialization.data(withJSONObject: users, options: .prettyPrinted),
           let jsonString = String(data: jsonData, encoding: .utf8) {
            return (200, jsonString)
        }
        return (500, "Internal Server Error")
    }

    private func handleGetUser(id: Int) -> (Int, String) {
        if let users = data["users"] as? [[String: Any]],
           let user = users.first(where: { ($0["id"] as? Int) == id }),
           let jsonData = try? JSONSerialization.data(withJSONObject: user, options: .prettyPrinted),
           let jsonString = String(data: jsonData, encoding: .utf8) {
            return (200, jsonString)
        }
        return (404, "User not found")
    }

    private func handleCreateUser(body: String?) -> (Int, String) {
        guard let body = body,
              let bodyData = body.data(using: .utf8),
              let user = try? JSONSerialization.jsonObject(with: bodyData) as? [String: Any] else {
            return (400, "Invalid request body")
        }

        var users = (data["users"] as? [[String: Any]]) ?? []
        let newUser = user.merging(["id": users.count + 1]) { _, new in new }
        users.append(newUser)
        data["users"] = users

        if let jsonData = try? JSONSerialization.data(withJSONObject: newUser, options: .prettyPrinted),
           let jsonString = String(data: jsonData, encoding: .utf8) {
            return (201, jsonString)
        }

        return (500, "Internal Server Error")
    }
}

// Main demonstration
func demonstrateHTTPServer() {
    print("=== macOS Swift HTTP Server Examples ===")

    let server = SimpleHTTPServer()

    // Start server on port 8080
    server.start(port: 8080)

    print("\nServer is running. Test with:")
    print("  curl http://localhost:8080/")
    print("  curl http://localhost:8080/about")
    print("  curl http://localhost:8080/json")
    print("  curl http://localhost:8080/time")

    // Keep server running
    print("\nPress Ctrl+C to stop the server")
    RunLoop.current.run()

    // Server cleanup on exit (in practice, use signal handlers)
    // server.stop()
}

// Uncomment to run server
// demonstrateHTTPServer()

print("\nNote: HTTP server examples provided. Uncomment demonstrateHTTPServer() to start server.")