首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS GCDAsyncUdpSocket 發送 UDP 數據包:客戶端完整實現代碼

     編輯:程式設計綜合問答

依賴集成

CocoaPods: pod 'CocoaAsyncSocket'
Swift Package Manager: https://github.com/robbiehanson/CocoaAsyncSocket

完整客戶端實現


import CocoaAsyncSocket

class UDPClient: NSObject, GCDAsyncUdpSocketDelegate {
    private var udpSocket: GCDAsyncUdpSocket!
    private let host = "192.168.10.111"
    private let port: UInt16 = 550

    override init() {
        super.init()
        setupSocket()
    }

    private func setupSocket() {
        udpSocket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
        do {
            // 綁定本地端口 (可選,僅接收回覆時需要)
            try udpSocket.bind(toPort: 0) // 0 = 系統自動分配
            try udpSocket.beginReceiving()
            print("UDP Socket ready")
        } catch {
            print("Socket setup failed: \(error)")
        }
    }

    func sendMessage(_ message: String) {
        guard let data = message.data(using: .utf8) else { return }
        udpSocket.send(data, toHost: host, port: port, withTimeout: -1, tag: 1)
    }

    // MARK: - GCDAsyncUdpSocketDelegate
    func udpSocket(_ sock: GCDAsyncUdpSocket, didSendDataWithTag tag: Int) {
        print("發送成功 tag: \(tag)")
    }

    func udpSocket(_ sock: GCDAsyncUdpSocket, didNotSendDataWithTag tag: Int, dueToError error: Error?) {
        print("發送失敗: \(error?.localizedDescription ?? "unknown")")
    }

    func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
        // 接收服務器回覆
        if let response = String(data: data, encoding: .utf8) {
            print("收到回覆: \(response)")
        }
    }
}

// 使用
let client = UDPClient()
client.sendMessage("Hello World")

Objective-C 版本


// .h
#import 
@class GCDAsyncUdpSocket;

@interface UDPClient : NSObject 
@property (nonatomic, strong) GCDAsyncUdpSocket *udpSocket;
- (void)sendMessage:(NSString *)message;
@end

// .m
#import "UDPClient.h"
#import "GCDAsyncUdpSocket.h"

@implementation UDPClient

- (instancetype)init {
    self = [super init];
    if (self) {
        _udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
        NSError *error = nil;
        [_udpSocket bindToPort:0 error:&error]; // 綁定任意端口
        [_udpSocket beginReceiving:&error];
        if (error) NSLog(@"Socket error: %@", error);
    }
    return self;
}

- (void)sendMessage:(NSString *)message {
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    [_udpSocket sendData:data toHost:@"192.168.10.111" port:550 withTimeout:-1 tag:1];
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(int)tag {
    NSLog(@"Sent tag: %d", tag);
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(int)tag dueToError:(NSError *)error {
    NSLog(@"Send failed: %@", error);
}

- (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext {
    NSString *resp = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSLog(@"Received: %@", resp);
}
@end

服務端配對代碼 (C# 參考)


// C# Server
var server = new UdpClient(8585);
var groupEP = new IPEndPoint(IPAddress.Any, 8585);
byte[] bytes = server.Receive(ref groupEP);
string msg = Encoding.UTF8.GetString(bytes);
Console.WriteLine("Received: " + msg);

// 回覆
byte[] reply = Encoding.UTF8.GetBytes("ACK");
server.Send(reply, reply.Length, groupEP);

關鍵注意點

項目說明
權限Info.plist 添加 NSLocalNetworkUsageDescription (iOS 14+ 本地網絡權限)
綁定端口僅需接收回覆時綁定,單向發送可不綁定
廣播需 enableBroadcast(true) 並發送至 255.255.255.255
IPv6GCDAsyncSocket 支持雙棧,傳入主機名自動解析
生命周期持有強引用防止被釋放,deinit 中 close()

現代替代:Network 框架


import Network

let connection = NWConnection(host: "192.168.10.111", port: 550, using: .udp)
connection.stateUpdateHandler = { state in
    switch state {
    case .ready:
        connection.send(content: "Hello World".data(using: .utf8), completion: .contentProcessed({ _ in }))
        connection.receiveMessage { data, _, _, _ in
            if let data = data, let resp = String(data: data, encoding: .utf8) {
                print("Reply: \(resp)")
            }
        }
    case .failed(let err): print("Failed: \(err)")
    default: break
    }
}
connection.start(queue: .main)

優點:系統級框架、無第三方依賴、支援 TLS/DTLS、更現代的 API 設計。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved