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")
// .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# 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 |
| IPv6 | GCDAsyncSocket 支持雙棧,傳入主機名自動解析 |
| 生命周期 | 持有強引用防止被釋放,deinit 中 close() |
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 設計。