// // XUDPServer.m // xcmd // // Created by mac on 2025/2/17. // #import #import "XUDPServer.h" #import "UDPHandler.h" #define PORT 6001 @interface XUDPServer() { @private GCDAsyncUdpSocket *serverSocket; dispatch_queue_t serverQueue; // 专用队列 dispatch_source_t restartTimer; // 重用的定时器 NSUInteger restartAttempts; } @end @implementation XUDPServer +(instancetype)sharedInstance { static XUDPServer* _sharedInstance = nil; static dispatch_once_t oncePredicate; dispatch_once (&oncePredicate, ^{ _sharedInstance = [[XUDPServer alloc] init]; }); return _sharedInstance; } -(instancetype)init { if (self = [super init]) { restartAttempts = 0; // 创建串行队列,避免并发问题 serverQueue = dispatch_queue_create("com.xudpserver.queue", DISPATCH_QUEUE_SERIAL); return self; } return nil; } - (void)start { // 使用专用队列,确保操作串行化 dispatch_async(serverQueue, ^{ [self _startInternal]; }); } - (void) _startInternal { NSLog(@"XS- start udp server"); // 避免重复创建 if (serverSocket && !serverSocket.isClosed) { NSLog(@"UDP server already running"); return; } [self _stopInternal]; serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:serverQueue]; NSError *error = nil; if (![serverSocket bindToPort:PORT error:&error]) { NSLog(@"❌ Error binding to port %d: %@", PORT, error); if (error.code == 48) { [self _tryFallbackPorts]; return; } [self _scheduleRestartWithBackoff]; return; } if (![serverSocket beginReceiving:&error]) { NSLog(@"❌ Error starting server (recv): %@", error); [self _scheduleRestartWithBackoff]; return; } restartAttempts = 0; // 重置重试计数 NSLog(@"✅ UDP server started successfully on port %d", PORT); } - (void)stop { dispatch_async(serverQueue, ^{ [self _stopInternal]; }); } - (void)_stopInternal { // 取消待处理的重启定时器 [self _cancelRestartTimer]; if (serverSocket) { NSLog(@"Stopping UDP server on port %d", PORT); [serverSocket close]; serverSocket = nil; } } #pragma mark - Restart Logic with Backoff - (void)_cancelRestartTimer { if (restartTimer) { dispatch_source_cancel(restartTimer); restartTimer = nil; } } - (void)_scheduleRestartWithBackoff { // 取消之前的定时器 [self _cancelRestartTimer]; // 限制重试次数 const NSUInteger maxAttempts = 10; if (restartAttempts >= maxAttempts) { NSLog(@"❌ Maximum restart attempts (%lu) reached, giving up", (unsigned long)maxAttempts); return; } restartAttempts++; // 指数退避:1s, 2s, 4s, 8s, 16s, 最大60s NSTimeInterval delay = MIN(pow(2, restartAttempts - 1), 60.0); NSLog(@"⏰ Scheduling restart attempt %lu in %.1f seconds", (unsigned long)restartAttempts, delay); // 使用 dispatch_source 创建可取消的定时器 restartTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, serverQueue); dispatch_source_set_timer(restartTimer, dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0.1 * NSEC_PER_SEC); dispatch_source_set_event_handler(restartTimer, ^{ [self _startInternal]; }); dispatch_resume(restartTimer); } - (void)_tryFallbackPorts { NSLog(@"❌ No available ports found"); [self _scheduleRestartWithBackoff]; } - (void)scheduleRestart { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), serverQueue, ^{ [self start]; }); } // 网络连接成功后 自动回调 - (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address { NSLog(@"已连接到用户:ip:%@",[[NSString alloc]initWithData:address encoding:NSUTF8StringEncoding]); } -(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext { @autoreleasepool { // 安全的字符串转换 NSString *datastr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; if (!datastr) { NSLog(@"Failed to decode received data"); return; } NSLog(@"XS- UDP Request>>>> %@", datastr); UDPHandler *handle = [UDPHandler sharedInstance]; NSString *res = [handle handle:datastr]; if (res) { NSData *responseData = [res dataUsingEncoding:NSUTF8StringEncoding]; [sock sendData:responseData toAddress:address withTimeout:10.0 tag:300]; } } } - (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error { NSLog(@"didNotConnect:%@", error); } - (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag { NSLog(@"didSendDataWithTag:%ld", tag); } - (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error { NSLog(@"didNotSendDataWithTag:%@", error); } - (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error { NSLog(@"withError:%@", error); if (error) { [self scheduleRestart]; // 自动重连 } } - (void)dealloc { [self _cancelRestartTimer]; [self _stopInternal]; } @end