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

iOS网络新手求助:Swift中用CocoaAsyncSocket等库搭建TCP服务端/客户端实例

Swift TCP Client/Server Examples (Including Swift 3 + CocoaAsyncSocket)

Hey there! I totally get how frustrating it can be when you're starting out with iOS TCP development and hit roadblocks with those libraries. Let me walk you through concrete examples to get you up and running, with a deep dive into using CocoaAsyncSocket in Swift 3.

First: Setup for CocoaAsyncSocket in Swift 3

Before diving into code, make sure you've got CocoaAsyncSocket added to your project:

  • Use CocoaPods: Add pod 'CocoaAsyncSocket' to your Podfile, run pod install, then open the .xcworkspace file.
  • Create a bridging header if you don't already have one, and add #import "GCDAsyncSocket.h" to it. This lets Swift interact with the Objective-C library.

TCP Client with CocoaAsyncSocket (Swift 3)

Here's a complete client implementation that connects to a server, sends data, and listens for responses:

import UIKit

class TCPClient: NSObject, GCDAsyncSocketDelegate {
    var socket: GCDAsyncSocket!
    let host = "localhost" // Replace with your server IP/hostname
    let port: UInt16 = 8080

    override init() {
        super.init()
        socket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
    }

    func connect() {
        do {
            try socket.connect(toHost: host, onPort: port)
            print("Attempting to connect to \(host):\(port)")
        } catch let error {
            print("Connection failed: \(error.localizedDescription)")
        }
    }

    func sendMessage(_ message: String) {
        guard let data = message.data(using: .utf8) else { return }
        socket.write(data, withTimeout: -1, tag: 0)
        // After writing, we can read the response
        socket.readData(toLength: UInt(data.count), withTimeout: -1, tag: 0)
    }

    // MARK: - GCDAsyncSocketDelegate
    func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {
        print("Successfully connected to \(host):\(port)")
        // Send an initial message if needed
        sendMessage("Hello from Swift 3 Client!")
    }

    func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
        if let response = String(data: data, encoding: .utf8) {
            print("Received response: \(response)")
        }
        // Keep listening for more data
        sock.readData(toLength: UInt(data.count), withTimeout: -1, tag: 0)
    }

    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError error: Error?) {
        print("Disconnected. Error: \(error?.localizedDescription ?? "None")")
    }
}

// Usage in your ViewController:
// let client = TCPClient()
// client.connect()
// Later, send messages with client.sendMessage("Your message here")

TCP Server with CocoaAsyncSocket (Swift 3)

This server listens for incoming connections, reads client messages, and sends responses:

import UIKit

class TCPServer: NSObject, GCDAsyncSocketDelegate {
    var serverSocket: GCDAsyncSocket!
    let port: UInt16 = 8080
    var connectedSockets = [GCDAsyncSocket]()

    override init() {
        super.init()
        serverSocket = GCDAsyncSocket(delegate: self, delegateQueue: DispatchQueue.main)
    }

    func startListening() {
        do {
            try serverSocket.accept(onPort: port)
            print("Server listening on port \(port)")
        } catch let error {
            print("Failed to start server: \(error.localizedDescription)")
        }
    }

    // MARK: - GCDAsyncSocketDelegate
    func socket(_ sock: GCDAsyncSocket, didAcceptNewSocket newSocket: GCDAsyncSocket) {
        print("New client connected: \(newSocket.connectedHost ?? "Unknown"):\(newSocket.connectedPort)")
        connectedSockets.append(newSocket)
        // Start reading data from the new client
        newSocket.readData(toLength: 1024, withTimeout: -1, tag: 0)
    }

    func socket(_ sock: GCDAsyncSocket, didRead data: Data, withTag tag: Int) {
        guard let message = String(data: data, encoding: .utf8) else {
            print("Received invalid data")
            sock.readData(toLength: 1024, withTimeout: -1, tag: 0)
            return
        }
        print("Received from client: \(message)")

        // Send a response back
        let response = "Server received: \(message)"
        if let responseData = response.data(using: .utf8) {
            sock.write(responseData, withTimeout: -1, tag: 0)
        }

        // Continue listening for more messages
        sock.readData(toLength: 1024, withTimeout: -1, tag: 0)
    }

    func socketDidDisconnect(_ sock: GCDAsyncSocket, withError error: Error?) {
        print("Client disconnected: \(sock.connectedHost ?? "Unknown")")
        if let index = connectedSockets.firstIndex(of: sock) {
            connectedSockets.remove(at: index)
        }
    }
}

// Usage in your ViewController:
// let server = TCPServer()
// server.startListening()

Bonus: Pure Swift TCP Client (No Third-Party Libraries)

If you want to try a native implementation without external libraries, here's a simple example:

import Foundation

class NativeTCPClient {
    var inputStream: InputStream?
    var outputStream: OutputStream?
    let host = "localhost"
    let port: UInt32 = 8080

    func setupConnection() {
        var readStream: Unmanaged<CFReadStream>?
        var writeStream: Unmanaged<CFWriteStream>?

        CFStreamCreatePairWithSocketToHost(nil, host as CFString, port, &readStream, &writeStream)

        inputStream = readStream?.takeRetainedValue()
        outputStream = writeStream?.takeRetainedValue()

        inputStream?.delegate = self
        outputStream?.delegate = self

        inputStream?.schedule(in: .main, forMode: .common)
        outputStream?.schedule(in: .main, forMode: .common)

        inputStream?.open()
        outputStream?.open()
    }

    func sendMessage(_ message: String) {
        guard let data = message.data(using: .utf8), let outputStream = outputStream else { return }
        let bytesWritten = data.withUnsafeBytes { buffer in
            outputStream.write(buffer.baseAddress!.assumingMemoryBound(to: UInt8.self), maxLength: data.count)
        }
        print("Wrote \(bytesWritten) bytes")
    }
}

extension NativeTCPClient: StreamDelegate {
    func stream(_ aStream: Stream, handle eventCode: Stream.Event) {
        switch eventCode {
        case .openCompleted:
            print("Stream opened")
        case .hasBytesAvailable:
            guard let inputStream = aStream as? InputStream else { return }
            var buffer = [UInt8](repeating: 0, count: 1024)
            let bytesRead = inputStream.read(&buffer, maxLength: buffer.count)
            if bytesRead > 0 {
                let response = String(bytes: buffer, encoding: .utf8)
                print("Received: \(response ?? "Invalid data")")
            }
        case .errorOccurred:
            print("Stream error: \(aStream.streamError?.localizedDescription ?? "Unknown")")
        case .endEncountered:
            print("Stream ended")
            aStream.close()
            aStream.remove(from: .main, forMode: .common)
        default:
            break
        }
    }
}

Quick Troubleshooting Tips

  • Firewall Issues: Make sure your server port is open, and if testing on a simulator/device, check local network permissions.
  • Threading: Both CocoaAsyncSocket and native streams use delegate queues—make sure you're handling UI updates on the main thread if needed.
  • Data Length: When reading data, if you don't know the exact length upfront, use readDataToData: instead of fixed lengths (for CocoaAsyncSocket, use a delimiter like "\n").

内容的提问来源于stack exchange,提问作者Ali A. Jalil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:53:04