You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift实现非WebSocket的Socket客户端对接Python Socket服务器

How to Build a Raw TCP Socket Client in Swift (No WebSockets Needed)

Hey there! I totally get where you're stuck—when you're used to Python's dead-simple socket module, hunting for a raw TCP/UDP socket implementation in Swift can feel frustrating when all the search results are pushing WebSocket libraries. Let's fix that: you don't need any external packages—Swift's Foundation framework has everything you need to build a basic non-WebSocket socket client that talks directly to your Python server.

1. Use Swift's Native BSD Socket APIs

Under the hood, Swift (via Foundation) exposes the same BSD socket interface that Python's socket module uses. This means you can create, connect, send, and receive data just like you do in Python—no WebSocket framing or extra layers required.

2. Complete TCP Client Implementation

Here's a practical, thread-safe example that connects to your Python server, sends messages, and listens for responses. We'll use Grand Central Dispatch (GCD) to keep network operations off the main thread (critical for keeping your iOS app responsive):

import Foundation

class RawTCPClient {
    private var host: String
    private var port: Int
    private var socketFD: Int32 = -1
    
    init(host: String, port: Int) {
        self.host = host
        self.port = port
    }
    
    // Establish connection to server
    func connect(completion: @escaping (Bool) -> Void) {
        DispatchQueue.global(qos: .background).async {
            // Create TCP socket
            self.socketFD = socket(AF_INET, SOCK_STREAM, 0)
            guard self.socketFD != -1 else {
                print("Failed to create socket")
                DispatchQueue.main.async { completion(false) }
                return
            }
            
            // Configure server address
            var serverAddr = sockaddr_in()
            serverAddr.sin_family = sa_family_t(AF_INET)
            serverAddr.sin_port = UInt16(self.port).bigEndian // Convert to network byte order
            
            // Resolve host to IP address
            guard let ipAddr = self.resolveHost(toIP: self.host) else {
                print("Couldn't resolve host address")
                DispatchQueue.main.async { completion(false) }
                return
            }
            serverAddr.sin_addr = ipAddr
            
            // Connect to server
            let connectionResult = connect(
                self.socketFD,
                sockaddr_cast(&serverAddr),
                socklen_t(MemoryLayout<sockaddr_in>.size)
            )
            
            DispatchQueue.main.async {
                completion(connectionResult == 0)
            }
        }
    }
    
    // Send data to server
    func send(data: Data, completion: @escaping (Bool) -> Void) {
        DispatchQueue.global(qos: .background).async {
            guard self.socketFD != -1 else {
                print("Not connected to server")
                DispatchQueue.main.async { completion(false) }
                return
            }
            
            let bytesSent = send(self.socketFD, data.bytes, data.count, 0)
            DispatchQueue.main.async {
                completion(bytesSent == data.count)
            }
        }
    }
    
    // Receive data from server
    func receive(maxBufferSize: Int = 1024, completion: @escaping (Data?) -> Void) {
        DispatchQueue.global(qos: .background).async {
            guard self.socketFD != -1 else {
                print("Not connected to server")
                DispatchQueue.main.async { completion(nil) }
                return
            }
            
            var buffer = [UInt8](repeating: 0, count: maxBufferSize)
            let bytesReceived = recv(self.socketFD, &buffer, maxBufferSize, 0)
            
            guard bytesReceived > 0 else {
                print("Connection closed or error receiving data")
                DispatchQueue.main.async { completion(nil) }
                return
            }
            
            let receivedData = Data(buffer[0..<bytesReceived])
            DispatchQueue.main.async {
                completion(receivedData)
            }
        }
    }
    
    // Close the connection
    func disconnect() {
        if socketFD != -1 {
            close(socketFD)
            socketFD = -1
        }
    }
    
    // Helper: Resolve hostname to IPv4 address
    private func resolveHost(toIP host: String) -> in_addr? {
        var hints = addrinfo(
            ai_flags: 0,
            ai_family: AF_INET,
            ai_socktype: SOCK_STREAM,
            ai_protocol: IPPROTO_TCP,
            ai_addrlen: 0,
            ai_canonname: nil,
            ai_addr: nil,
            ai_next: nil
        )
        
        var infoPtr: UnsafeMutablePointer<addrinfo>?
        defer { freeaddrinfo(infoPtr) }
        
        let resolveResult = getaddrinfo(host, nil, &hints, &infoPtr)
        guard resolveResult == 0, let info = infoPtr else { return nil }
        
        let sockaddrIn = UnsafeMutablePointer<sockaddr_in>(OpaquePointer(info.pointee.ai_addr))
        return sockaddrIn.pointee.sin_addr
    }
}

// Example usage
let client = RawTCPClient(host: "192.168.1.100", port: 5000) // Replace with your server IP/port
client.connect { success in
    if success {
        print("Connected to Python server!")
        
        // Send a test message
        let message = "Hello from Swift TCP Client!"
        if let messageData = message.data(using: .utf8) {
            client.send(data: messageData) { sendSuccess in
                if sendSuccess {
                    print("Message sent")
                    
                    // Wait for response
                    client.receive { responseData in
                        if let data = responseData, let response = String(data: data, encoding: .utf8) {
                            print("Received response: \(response)")
                        }
                    }
                }
            }
        }
    } else {
        print("Failed to connect")
    }
}

// Remember to disconnect when finished (e.g., in viewWillDisappear)
// client.disconnect()

3. Critical Compatibility Tips for Your Python Server

  • Match Socket Type: If your Python server uses TCP (socket.SOCK_STREAM), the example above works perfectly. If you're using UDP, swap SOCK_STREAM with SOCK_DGRAM in the Swift code, and use sendto/recvfrom instead of send/recv.
  • Consistent Encoding: Both your Python server and Swift client should use the same string encoding (UTF-8 is standard) when converting between strings and raw bytes.
  • Threading Handling: Your Python server uses threading to manage multiple clients—make sure your Swift client handles disconnections gracefully and doesn't block the main thread (the example uses GCD to avoid this).

4. Why You're Seeing Mostly WebSocket Libraries

WebSockets are popular for real-time apps because they add a standardized framing layer and keep-alive mechanisms on top of TCP. But for a raw socket setup like your Python socket implementation, Swift's native APIs are all you need—no third-party libraries required.

内容的提问来源于stack exchange,提问作者Adam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 04:02:05