增加尝试其他端口
This commit is contained in:
parent
fa49dcac96
commit
a8a122a6e0
@ -6,5 +6,5 @@ Author: XYZShell
|
|||||||
Section: Utilities
|
Section: Utilities
|
||||||
Tag: role::developer
|
Tag: role::developer
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Version: 0.0.7-10-61+debug
|
Version: 0.0.7-10-62+debug
|
||||||
Installed-Size: 1600
|
Installed-Size: 1604
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
./packages/com.xyzshell.ioscontrol_0.0.7-10-61+debug_iphoneos-arm.deb
|
./packages/com.xyzshell.ioscontrol_0.0.7-10-62+debug_iphoneos-arm.deb
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
|||||||
61
|
62
|
||||||
@ -1,39 +1,36 @@
|
|||||||
//
|
|
||||||
// XUDPServer.m
|
|
||||||
// xcmd
|
|
||||||
//
|
|
||||||
// Created by mac on 2025/2/17.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#include <complex.h>
|
|
||||||
#import <sys/socket.h>
|
#import <sys/socket.h>
|
||||||
|
#import <netinet/in.h>
|
||||||
|
#import <arpa/inet.h>
|
||||||
|
|
||||||
#import "XUDPServer.h"
|
#import "XUDPServer.h"
|
||||||
#import "UDPHandler.h"
|
#import "UDPHandler.h"
|
||||||
|
|
||||||
|
|
||||||
#define FALLBACK_PORT_START 6001
|
#define FALLBACK_PORT_START 6001
|
||||||
#define FALLBACK_PORT_END 7000
|
#define FALLBACK_PORT_END 7000
|
||||||
|
|
||||||
#define PORT 6001
|
#define PORT 6001
|
||||||
|
#define SEND_TIMEOUT 5.0 // 发送超时时间
|
||||||
|
|
||||||
@interface XUDPServer() {
|
@interface XUDPServer() {
|
||||||
@private
|
@private
|
||||||
GCDAsyncUdpSocket *serverSocket;
|
GCDAsyncUdpSocket *serverSocket;
|
||||||
dispatch_queue_t serverQueue; // 专用队列
|
dispatch_queue_t serverQueue;
|
||||||
dispatch_source_t restartTimer; // 重用的定时器
|
dispatch_source_t restartTimer;
|
||||||
NSUInteger restartAttempts;
|
NSUInteger restartAttempts;
|
||||||
uint16_t currentPort;
|
uint16_t currentPort;
|
||||||
|
NSTimer *healthCheckTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSDictionary *> *pendingSends;
|
||||||
|
@property (nonatomic, assign) long currentTag;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation XUDPServer
|
@implementation XUDPServer
|
||||||
|
|
||||||
+(instancetype)sharedInstance
|
#pragma mark - Singleton
|
||||||
{
|
|
||||||
|
+ (instancetype)sharedInstance {
|
||||||
static XUDPServer* _sharedInstance = nil;
|
static XUDPServer* _sharedInstance = nil;
|
||||||
static dispatch_once_t oncePredicate;
|
static dispatch_once_t oncePredicate;
|
||||||
dispatch_once(&oncePredicate, ^{
|
dispatch_once(&oncePredicate, ^{
|
||||||
@ -45,16 +42,19 @@
|
|||||||
- (instancetype)init {
|
- (instancetype)init {
|
||||||
if (self = [super init]) {
|
if (self = [super init]) {
|
||||||
restartAttempts = 0;
|
restartAttempts = 0;
|
||||||
// 创建串行队列,避免并发问题
|
|
||||||
currentPort = PORT;
|
currentPort = PORT;
|
||||||
|
_currentTag = 0;
|
||||||
|
_pendingSends = [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
|
// 创建串行队列,避免并发问题
|
||||||
serverQueue = dispatch_queue_create("com.xudpserver.queue", DISPATCH_QUEUE_SERIAL);
|
serverQueue = dispatch_queue_create("com.xudpserver.queue", DISPATCH_QUEUE_SERIAL);
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)start {
|
- (void)start {
|
||||||
// 使用专用队列,确保操作串行化
|
|
||||||
dispatch_async(serverQueue, ^{
|
dispatch_async(serverQueue, ^{
|
||||||
[self _startInternal];
|
[self _startInternal];
|
||||||
});
|
});
|
||||||
@ -65,10 +65,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)_startInternal {
|
- (void)_startInternal {
|
||||||
NSLog(@"XS- start udp server");
|
NSLog(@"XS- Starting UDP server on port %d", currentPort);
|
||||||
|
|
||||||
// 避免重复创建
|
// 避免重复创建
|
||||||
if (serverSocket && !serverSocket.isClosed) {
|
if (serverSocket && !serverSocket.isClosed) {
|
||||||
NSLog(@"UDP server already running");
|
NSLog(@"⚠️ UDP server already running on port %d", currentPort);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,21 +77,21 @@
|
|||||||
|
|
||||||
serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
|
serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
|
||||||
delegateQueue:serverQueue];
|
delegateQueue:serverQueue];
|
||||||
// ⭐️ 关键修复:启用地址重用
|
|
||||||
NSError *error = nil;
|
NSError *error = nil;
|
||||||
|
|
||||||
|
// ⭐️ 启用端口重用
|
||||||
if (![serverSocket enableReusePort:YES error:&error]) {
|
if (![serverSocket enableReusePort:YES error:&error]) {
|
||||||
NSLog(@"❌ Error enabling reuse port: %@", error);
|
NSLog(@"❌ Error enabling reuse port: %@", error);
|
||||||
}
|
}
|
||||||
// ⭐️ 设置 SO_REUSEADDR
|
|
||||||
int reuseOn = 1;
|
// ⭐️ 设置所有必要的socket选项
|
||||||
if (setsockopt([serverSocket socketFD], SOL_SOCKET, SO_REUSEADDR,
|
[self _configureSocketOptions];
|
||||||
&reuseOn, sizeof(reuseOn)) == -1) {
|
|
||||||
NSLog(@"❌ Error setting SO_REUSEADDR");
|
// 尝试绑定到指定端口
|
||||||
}
|
|
||||||
if (![serverSocket bindToPort:currentPort error:&error]) {
|
if (![serverSocket bindToPort:currentPort error:&error]) {
|
||||||
NSLog(@"❌ Error binding to port %d: %@", currentPort, error);
|
NSLog(@"❌ Error binding to port %d: %@", currentPort, error);
|
||||||
|
|
||||||
// ⭐️ 绑定失败后清理 socket
|
|
||||||
[serverSocket close];
|
[serverSocket close];
|
||||||
serverSocket = nil;
|
serverSocket = nil;
|
||||||
|
|
||||||
@ -107,7 +108,6 @@
|
|||||||
if (![serverSocket beginReceiving:&error]) {
|
if (![serverSocket beginReceiving:&error]) {
|
||||||
NSLog(@"❌ Error starting server (recv): %@", error);
|
NSLog(@"❌ Error starting server (recv): %@", error);
|
||||||
|
|
||||||
// ⭐️ 接收失败后清理 socket
|
|
||||||
[serverSocket close];
|
[serverSocket close];
|
||||||
serverSocket = nil;
|
serverSocket = nil;
|
||||||
|
|
||||||
@ -115,10 +115,71 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
restartAttempts = 0; // 重置重试计数
|
restartAttempts = 0;
|
||||||
NSLog(@"✅ UDP server started successfully on port %d", currentPort);
|
NSLog(@"✅ UDP server started successfully on port %d", currentPort);
|
||||||
|
|
||||||
|
// ⭐️ 启动健康检查
|
||||||
|
[self _startHealthCheck];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐️ 配置所有socket选项
|
||||||
|
- (void)_configureSocketOptions {
|
||||||
|
if (!serverSocket) return;
|
||||||
|
|
||||||
|
int fd = [serverSocket socketFD];
|
||||||
|
if (fd == -1) {
|
||||||
|
NSLog(@"⚠️ Invalid socket file descriptor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 设置 SO_REUSEADDR - 允许快速重启,避免TIME_WAIT问题
|
||||||
|
int reuseAddr = 1;
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) == -1) {
|
||||||
|
NSLog(@"❌ Error setting SO_REUSEADDR: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 设置 SO_REUSEPORT - 允许多个socket绑定同一端口(某些系统)
|
||||||
|
int reusePort = 1;
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &reusePort, sizeof(reusePort)) == -1) {
|
||||||
|
NSLog(@"⚠️ SO_REUSEPORT not supported or error: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. ⭐️ 增加接收缓冲区大小,避免缓冲区溢出
|
||||||
|
int recvBufferSize = 256 * 1024; // 256KB
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvBufferSize, sizeof(recvBufferSize)) == -1) {
|
||||||
|
NSLog(@"⚠️ Failed to set receive buffer size: %s", strerror(errno));
|
||||||
|
} else {
|
||||||
|
// 验证实际设置的大小
|
||||||
|
socklen_t optlen = sizeof(recvBufferSize);
|
||||||
|
getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvBufferSize, &optlen);
|
||||||
|
NSLog(@"✅ Receive buffer size set to: %d bytes", recvBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. ⭐️ 增加发送缓冲区大小
|
||||||
|
int sendBufferSize = 256 * 1024; // 256KB
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, sizeof(sendBufferSize)) == -1) {
|
||||||
|
NSLog(@"⚠️ Failed to set send buffer size: %s", strerror(errno));
|
||||||
|
} else {
|
||||||
|
socklen_t optlen = sizeof(sendBufferSize);
|
||||||
|
getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, &optlen);
|
||||||
|
NSLog(@"✅ Send buffer size set to: %d bytes", sendBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. ⭐️ 设置 SO_NOSIGPIPE - 防止写入关闭的socket时产生SIGPIPE信号
|
||||||
|
#ifdef SO_NOSIGPIPE
|
||||||
|
int noSigpipe = 1;
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &noSigpipe, sizeof(noSigpipe)) == -1) {
|
||||||
|
NSLog(@"⚠️ Failed to set SO_NOSIGPIPE: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 6. ⭐️ 设置非阻塞模式(GCDAsyncUdpSocket通常已设置,但确保一下)
|
||||||
|
int flags = fcntl(fd, F_GETFL, 0);
|
||||||
|
if (flags != -1) {
|
||||||
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)stop {
|
- (void)stop {
|
||||||
dispatch_async(serverQueue, ^{
|
dispatch_async(serverQueue, ^{
|
||||||
[self _stopInternal];
|
[self _stopInternal];
|
||||||
@ -126,20 +187,87 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)_stopInternal {
|
- (void)_stopInternal {
|
||||||
|
NSLog(@"XS- Stopping UDP server on port %d", currentPort);
|
||||||
|
|
||||||
[self _cancelRestartTimer];
|
[self _cancelRestartTimer];
|
||||||
|
[self _stopHealthCheck];
|
||||||
|
|
||||||
if (serverSocket) {
|
if (serverSocket) {
|
||||||
NSLog(@"Stopping UDP server on port %d", currentPort);
|
// ⭐️ 设置SO_LINGER为0,强制立即关闭,避免TIME_WAIT
|
||||||
|
int fd = [serverSocket socketFD];
|
||||||
|
if (fd != -1) {
|
||||||
|
struct linger lingerOption = {1, 0}; // l_onoff=1, l_linger=0
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lingerOption, sizeof(lingerOption)) == -1) {
|
||||||
|
NSLog(@"⚠️ Failed to set SO_LINGER: %s", strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ⭐️ 确保完全关闭
|
|
||||||
if (!serverSocket.isClosed) {
|
if (!serverSocket.isClosed) {
|
||||||
[serverSocket close];
|
[serverSocket close];
|
||||||
}
|
}
|
||||||
|
|
||||||
serverSocket = nil;
|
serverSocket = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[_pendingSends removeAllObjects];
|
||||||
}
|
}
|
||||||
#pragma mark - Restart Logic with Backoff
|
|
||||||
|
#pragma mark - Health Check
|
||||||
|
|
||||||
|
// ⭐️ 健康检查
|
||||||
|
- (void)_startHealthCheck {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (self->healthCheckTimer) {
|
||||||
|
[self->healthCheckTimer invalidate];
|
||||||
|
}
|
||||||
|
|
||||||
|
self->healthCheckTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
|
||||||
|
target:self
|
||||||
|
selector:@selector(_performHealthCheck)
|
||||||
|
userInfo:nil
|
||||||
|
repeats:YES];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_stopHealthCheck {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
if (self->healthCheckTimer) {
|
||||||
|
[self->healthCheckTimer invalidate];
|
||||||
|
self->healthCheckTimer = nil;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)_performHealthCheck {
|
||||||
|
dispatch_async(serverQueue, ^{
|
||||||
|
if (!self->serverSocket || self->serverSocket.isClosed) {
|
||||||
|
NSLog(@"⚠️ Health check failed: socket is closed");
|
||||||
|
[self _startInternal];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐️ 检查socket状态
|
||||||
|
int fd = [self->serverSocket socketFD];
|
||||||
|
if (fd == -1) {
|
||||||
|
NSLog(@"⚠️ Health check failed: invalid socket");
|
||||||
|
[self _startInternal];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ⭐️ 检查端口是否仍然绑定
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
socklen_t addrLen = sizeof(addr);
|
||||||
|
if (getsockname(fd, (struct sockaddr *)&addr, &addrLen) == -1) {
|
||||||
|
NSLog(@"⚠️ Health check failed: socket not bound");
|
||||||
|
[self _startInternal];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"✅ Health check passed for port %d", self->currentPort);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Restart Logic
|
||||||
|
|
||||||
- (void)_cancelRestartTimer {
|
- (void)_cancelRestartTimer {
|
||||||
if (restartTimer) {
|
if (restartTimer) {
|
||||||
@ -149,10 +277,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)_scheduleRestartWithBackoff {
|
- (void)_scheduleRestartWithBackoff {
|
||||||
// 取消之前的定时器
|
|
||||||
[self _cancelRestartTimer];
|
[self _cancelRestartTimer];
|
||||||
|
|
||||||
// 限制重试次数
|
|
||||||
const NSUInteger maxAttempts = 10;
|
const NSUInteger maxAttempts = 10;
|
||||||
if (restartAttempts >= maxAttempts) {
|
if (restartAttempts >= maxAttempts) {
|
||||||
NSLog(@"❌ Maximum restart attempts (%lu) reached, giving up",
|
NSLog(@"❌ Maximum restart attempts (%lu) reached, giving up",
|
||||||
@ -162,13 +288,11 @@
|
|||||||
|
|
||||||
restartAttempts++;
|
restartAttempts++;
|
||||||
|
|
||||||
// 指数退避:1s, 2s, 4s, 8s, 16s, 最大60s
|
|
||||||
NSTimeInterval delay = MIN(pow(2, restartAttempts - 1), 60.0);
|
NSTimeInterval delay = MIN(pow(2, restartAttempts - 1), 60.0);
|
||||||
|
|
||||||
NSLog(@"⏰ Scheduling restart attempt %lu in %.1f seconds",
|
NSLog(@"⏰ Scheduling restart attempt %lu in %.1f seconds",
|
||||||
(unsigned long)restartAttempts, delay);
|
(unsigned long)restartAttempts, delay);
|
||||||
|
|
||||||
// 使用 dispatch_source 创建可取消的定时器
|
|
||||||
restartTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, serverQueue);
|
restartTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, serverQueue);
|
||||||
|
|
||||||
dispatch_source_set_timer(restartTimer,
|
dispatch_source_set_timer(restartTimer,
|
||||||
@ -184,34 +308,53 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)_tryFallbackPorts {
|
- (void)_tryFallbackPorts {
|
||||||
|
NSLog(@"🔍 Searching for available fallback port...");
|
||||||
|
|
||||||
for (uint16_t port = FALLBACK_PORT_START; port <= FALLBACK_PORT_END; port++) {
|
for (uint16_t port = FALLBACK_PORT_START; port <= FALLBACK_PORT_END; port++) {
|
||||||
GCDAsyncUdpSocket *testSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:nil
|
// ⭐️ 检查端口是否真的可用
|
||||||
delegateQueue:serverQueue];
|
if ([self _isPortAvailable:port]) {
|
||||||
|
|
||||||
NSError *error = nil;
|
|
||||||
if ([testSocket bindToPort:port error:&error]) {
|
|
||||||
[testSocket close];
|
|
||||||
|
|
||||||
// 找到可用端口
|
|
||||||
serverSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
|
|
||||||
delegateQueue:serverQueue];
|
|
||||||
|
|
||||||
if ([serverSocket bindToPort:port error:&error] &&
|
|
||||||
[serverSocket beginReceiving:&error]) {
|
|
||||||
currentPort = port;
|
currentPort = port;
|
||||||
restartAttempts = 0;
|
NSLog(@"✅ Found available port: %d", port);
|
||||||
NSLog(@"✅ UDP server started on fallback port %d", currentPort);
|
[self _startInternal];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[testSocket close];
|
|
||||||
}
|
NSLog(@"❌ No available fallback ports found in range %d-%d",
|
||||||
NSLog(@"❌ No available ports found");
|
FALLBACK_PORT_START, FALLBACK_PORT_END);
|
||||||
[self _scheduleRestartWithBackoff];
|
[self _scheduleRestartWithBackoff];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐️ 检查端口是否可用(改进版)
|
||||||
|
- (BOOL)_isPortAvailable:(uint16_t)port {
|
||||||
|
int testSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (testSocket < 0) {
|
||||||
|
NSLog(@"⚠️ Cannot create test socket");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置SO_REUSEADDR
|
||||||
|
int reuseAddr = 1;
|
||||||
|
setsockopt(testSocket, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr));
|
||||||
|
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
int result = bind(testSocket, (struct sockaddr *)&addr, sizeof(addr));
|
||||||
|
close(testSocket);
|
||||||
|
|
||||||
|
if (result == 0) {
|
||||||
|
return YES;
|
||||||
|
} else {
|
||||||
|
if (errno == EADDRINUSE) {
|
||||||
|
NSLog(@"⚠️ Port %d is in use", port);
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)scheduleRestart {
|
- (void)scheduleRestart {
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)),
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)),
|
||||||
@ -220,62 +363,157 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - GCDAsyncUdpSocket Delegate
|
||||||
|
|
||||||
// 网络连接成功后 自动回调
|
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address {
|
||||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address
|
NSLog(@"✅ Connected to client");
|
||||||
{
|
|
||||||
NSLog(@"已连接到用户:ip:%@",[[NSString alloc]initWithData:address encoding:NSUTF8StringEncoding]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
|
- (void)udpSocket:(GCDAsyncUdpSocket *)sock
|
||||||
{
|
didReceiveData:(NSData *)data
|
||||||
|
fromAddress:(NSData *)address
|
||||||
|
withFilterContext:(id)filterContext {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
// 安全的字符串转换
|
// ⭐️ 检查数据大小,防止超大包
|
||||||
NSString *datastr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
if (data.length > 65507) { // UDP最大包大小
|
||||||
if (!datastr) {
|
NSLog(@"⚠️ Received oversized packet: %lu bytes", (unsigned long)data.length);
|
||||||
NSLog(@"Failed to decode received data");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSLog(@"XS- UDP Request>>>> %@", datastr);
|
NSString *datastr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||||
|
if (!datastr) {
|
||||||
|
NSLog(@"⚠️ Failed to decode received data (length: %lu)", (unsigned long)data.length);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"📨 UDP Request from %@: %@",
|
||||||
|
[self _addressToString:address],
|
||||||
|
[datastr substringToIndex:MIN(100, datastr.length)]);
|
||||||
|
|
||||||
|
// ⭐️ 异步处理请求,避免阻塞接收
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
UDPHandler *handle = [UDPHandler sharedInstance];
|
UDPHandler *handle = [UDPHandler sharedInstance];
|
||||||
NSString *res = [handle handle:datastr];
|
NSString *res = [handle handle:datastr];
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
NSData *responseData = [res dataUsingEncoding:NSUTF8StringEncoding];
|
[self _sendResponse:res toAddress:address fromSocket:sock];
|
||||||
[sock sendData:responseData toAddress:address withTimeout:10.0 tag:300];
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐️ 发送响应(带超时和重试逻辑)
|
||||||
|
- (void)_sendResponse:(NSString *)response
|
||||||
|
toAddress:(NSData *)address
|
||||||
|
fromSocket:(GCDAsyncUdpSocket *)sock {
|
||||||
|
dispatch_async(serverQueue, ^{
|
||||||
|
if (!sock || sock.isClosed) {
|
||||||
|
NSLog(@"⚠️ Cannot send response: socket is closed");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NSData *responseData = [response dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError * _Nullable)error
|
if (!responseData) {
|
||||||
{
|
NSLog(@"⚠️ Failed to encode response");
|
||||||
NSLog(@"didNotConnect:%@", error);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐️ 检查响应大小
|
||||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
|
if (responseData.length > 65507) {
|
||||||
{
|
NSLog(@"⚠️ Response too large: %lu bytes (max 65507)",
|
||||||
NSLog(@"didSendDataWithTag:%ld", tag);
|
(unsigned long)responseData.length);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long tag = ++self->_currentTag;
|
||||||
|
|
||||||
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError * _Nullable)error
|
// 保存待发送数据
|
||||||
{
|
self->_pendingSends[@(tag)] = @{
|
||||||
NSLog(@"didNotSendDataWithTag:%@", error);
|
@"response": response,
|
||||||
|
@"address": address,
|
||||||
|
@"timestamp": @([[NSDate date] timeIntervalSince1970])
|
||||||
|
};
|
||||||
|
|
||||||
|
NSLog(@"📤 Sending response (tag: %ld, size: %lu bytes)",
|
||||||
|
tag, (unsigned long)responseData.length);
|
||||||
|
|
||||||
|
[sock sendData:responseData
|
||||||
|
toAddress:address
|
||||||
|
withTimeout:SEND_TIMEOUT
|
||||||
|
tag:tag];
|
||||||
|
|
||||||
|
// ⭐️ 设置超时检查
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((SEND_TIMEOUT + 1.0) * NSEC_PER_SEC)),
|
||||||
|
self->serverQueue, ^{
|
||||||
|
[self _checkSendTimeout:tag];
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ⭐️ 检查发送超时
|
||||||
|
- (void)_checkSendTimeout:(long)tag {
|
||||||
|
NSDictionary *pendingData = _pendingSends[@(tag)];
|
||||||
|
if (pendingData) {
|
||||||
|
NSTimeInterval timestamp = [pendingData[@"timestamp"] doubleValue];
|
||||||
|
NSTimeInterval elapsed = [[NSDate date] timeIntervalSince1970] - timestamp;
|
||||||
|
|
||||||
|
NSLog(@"⏱️ Send timeout for tag %ld (elapsed: %.1fs)", tag, elapsed);
|
||||||
|
[_pendingSends removeObjectForKey:@(tag)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error {
|
||||||
|
NSLog(@"❌ Did not connect: %@", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag {
|
||||||
|
NSLog(@"✅ Data sent successfully (tag: %ld)", tag);
|
||||||
|
[_pendingSends removeObjectForKey:@(tag)];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)udpSocket:(GCDAsyncUdpSocket *)sock
|
||||||
|
didNotSendDataWithTag:(long)tag
|
||||||
|
dueToError:(NSError *)error {
|
||||||
|
NSLog(@"❌ Failed to send data (tag: %ld): %@", tag, error);
|
||||||
|
|
||||||
|
[_pendingSends removeObjectForKey:@(tag)];
|
||||||
|
|
||||||
|
// ⭐️ 处理各种发送错误
|
||||||
|
if (error.code == 55) { // ENOBUFS
|
||||||
|
NSLog(@"⚠️ Buffer full (ENOBUFS) - system may be overloaded");
|
||||||
|
} else if (error.code == 57) { // ENOTCONN
|
||||||
|
NSLog(@"⚠️ Socket disconnected (ENOTCONN)");
|
||||||
|
[self _startInternal];
|
||||||
|
} else if (error.code == 64) { // EHOSTDOWN
|
||||||
|
NSLog(@"⚠️ Host is down (EHOSTDOWN)");
|
||||||
|
} else if (error.code == 65) { // EHOSTUNREACH
|
||||||
|
NSLog(@"⚠️ Host unreachable (EHOSTUNREACH)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error {
|
||||||
|
NSLog(@"⚠️ Socket closed. Error: %@", error);
|
||||||
|
|
||||||
|
if (sock == serverSocket) {
|
||||||
|
serverSocket = nil;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError * _Nullable)error
|
|
||||||
{
|
|
||||||
NSLog(@"withError:%@", error);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
[self scheduleRestart]; // 自动重连
|
NSLog(@"❌ Unexpected closure, scheduling restart");
|
||||||
|
[self scheduleRestart];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Utility Methods
|
||||||
|
|
||||||
|
// ⭐️ 将地址转换为可读字符串
|
||||||
|
- (NSString *)_addressToString:(NSData *)addressData {
|
||||||
|
struct sockaddr_in *addr = (struct sockaddr_in *)addressData.bytes;
|
||||||
|
char ipStr[INET_ADDRSTRLEN];
|
||||||
|
inet_ntop(AF_INET, &addr->sin_addr, ipStr, sizeof(ipStr));
|
||||||
|
return [NSString stringWithFormat:@"%s:%d", ipStr, ntohs(addr->sin_port)];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[self _cancelRestartTimer];
|
[self _cancelRestartTimer];
|
||||||
[self _stopInternal];
|
[self _stopInternal];
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user