topon 修改udp

This commit is contained in:
xsean 2025-11-05 11:07:10 +08:00
parent fab36c8600
commit 023b5ed7f6
8 changed files with 421 additions and 108 deletions

View File

@ -783,7 +783,7 @@ class YL_NetWorkManager{
// mdic["localIp"] = starManager.shared.adbrush_localip
//
// // let remoteIp = UserDefaults.standard.string(forKey: "kIP_key") ?? ""
// mdic["remoteIp"] = starManager.shared.remouteIP
// mdic["remoteIp"] = starManager.shared.remoteIp
//
// mdic["packageName"] = appId()
// mdic["adPlatform"] = "MAX"
@ -848,7 +848,7 @@ class YL_NetWorkManager{
mdic["deviceId"] = BbbAdManager.config.adbrush_deviceid
mdic["gaid"] = self.getGaid()
mdic["localIp"] = BbbAdManager.config.adbrush_localip
mdic["remoteIp"] = BbbAdManager.config.remouteIP
mdic["remoteIp"] = BbbAdManager.config.remoteIp
mdic["packageName"] = appId()
mdic["adPlatform"] = "MAX"
mdic["countryCode"] = countryCode
@ -917,7 +917,7 @@ class YL_NetWorkManager{
mdic["localIp"] = BbbAdManager.config.adbrush_localip
// let remoteIp = UserDefaults.standard.string(forKey: "kIP_key") ?? ""
mdic["remoteIp"] = BbbAdManager.config.remouteIP
mdic["remoteIp"] = BbbAdManager.config.remoteIp
mdic["packageName"] = appId()
mdic["adPlatform"] = "MAX"

View File

@ -46,7 +46,7 @@ class YL_PlayVC: UIViewController,UITextViewDelegate {
let deviceId = BbbAdManager.config.adbrush_deviceid ?? ""
deviceIdLab.text = "DeviceID:\(deviceId)"
let locIp = BbbAdManager.config.adbrush_localip ?? ""
let remoteIp = BbbAdManager.config.remouteIP
let remoteIp = BbbAdManager.config.remoteIp
ipLab.text = "LocIP:\(locIp),RemoteIp:\(remoteIp)"
if #available(iOS 14, *) {

View File

@ -29,7 +29,7 @@ class bConfig: NSObject {
var adbrush_local_url:String = "http://127.0.0.1:6000"
/// ip
var remouteIP:String = ""
var remoteIp:String = ""
/// dataId
var dataId:String = ""
@ -298,7 +298,7 @@ class BbbAdManager: NSObject {
BbbAdManager.config.adbrush_deviceid = bfaceDict["adbrush_deviceid"] as? String ?? ""
BbbAdManager.config.adbrush_localip = bfaceDict["adbrush_localip"] as? String ?? ""
BbbAdManager.config.remouteIP = bfaceDict["remoteIp"] as? String ?? ""
BbbAdManager.config.remoteIp = bfaceDict["remoteIp"] as? String ?? ""
BbbAdManager.config.adbrush_local_url = bfaceDict["adbrush_local_url"] as? String ?? "http://127.0.0.1:6000"

View File

@ -12,17 +12,29 @@
#import "CocoaAsyncSocket.h"
typedef void (^SendCallback) (NSString *msg);
@interface XUDPClient : NSObject<GCDAsyncUdpSocketDelegate>
@property (nonatomic, copy) SendCallback hintBlock;
// ⭐️ 单例方法
+ (instancetype)sharedInstance;
// 阻止使用 init 创建新实例
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
// 启动/停止
- (void)start;
- (void)stop;
// 发送方法
- (void)onShow:(NSDictionary *)data toPort:(uint16_t)port;
- (void)onEnd:(NSDictionary *)data toPort:(uint16_t)port;
- (void)send:(NSString *)msg toPort:(uint16_t)port;
// 接收消息回调
@property (nonatomic, copy, nullable) void(^hintBlock)(NSString *message);
- (void) onShow: (NSDictionary *)data;
- (void) onEnd: (NSDictionary *)data;
- (void) close;
@end
#endif /* XUDPClient_h */

View File

@ -1,138 +1,441 @@
//
// XUDPClient.m
// xcmd
//
// Created by mac on 2025/2/17.
//
#import <Foundation/Foundation.h>
#import "XUDPClient.h"
#import <sys/socket.h>
#import <netinet/in.h>
#import <arpa/inet.h>
#define HOST @"127.0.0.1"
#define PORT 6001
#define SEND_TIMEOUT 5.0 // ()
@interface XUDPClient() {
@private
GCDAsyncUdpSocket *_udpSocket;
dispatch_queue_t _clientQueue;
NSTimer *_healthCheckTimer;
BOOL _isConnected;
}
@property (nonatomic, strong) NSMutableDictionary<NSNumber *, NSDictionary *> *pendingSends;
@property (nonatomic, assign) long currentTag;
@end
@implementation XUDPClient
-(instancetype)init {
#pragma mark - Singleton
+ (instancetype)sharedInstance {
static XUDPClient *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[XUDPClient alloc] init];
});
return _sharedInstance;
}
// alloc/init
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
return [XUDPClient sharedInstance];
}
- (instancetype)copyWithZone:(NSZone *)zone {
return self;
}
- (instancetype)mutableCopyWithZone:(NSZone *)zone {
return self;
}
- (instancetype)init {
if (self = [super init]) {
self->_isConnected = NO;
self->_currentTag = 0;
self->_pendingSends = [NSMutableDictionary dictionary];
//
self->_clientQueue = dispatch_queue_create("com.xudpclient.queue", DISPATCH_QUEUE_SERIAL);
[self start];
return self;
[self startHealthCheck];
}
return nil;
return self;
}
- (void) start
{
if (!_udpSocket)
{
_udpSocket=nil;
- (void)start {
dispatch_async(_clientQueue, ^{
[self _startInternal];
});
}
- (void)_startInternal {
NSLog(@"XC- Starting UDP client");
// socket
if (_udpSocket) {
[_udpSocket close];
_udpSocket = nil;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
_udpSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:queue];
_udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self
delegateQueue:_clientQueue];
// ,TIME_WAIT
NSError *error = nil;
if (![_udpSocket bindToPort:0 error:&error])
{
NSLog(@"Error binding: %@", error);
if (![_udpSocket enableReusePort:YES error:&error]) {
NSLog(@"❌ Error enabling reuse port: %@", error);
}
// SO_REUSEADDR
[self _setSocketOptions];
//
if (![_udpSocket bindToPort:0 error:&error]) {
NSLog(@"❌ Error binding: %@", error);
[self _handleBindError:error];
return;
}
if (![_udpSocket beginReceiving:&error])
{
NSLog(@"Error receiving: %@", error);
if (![_udpSocket beginReceiving:&error]) {
NSLog(@"❌ Error receiving: %@", error);
[self _scheduleRestart];
return;
}
}
- (void) close
{
if(_udpSocket) {
[_udpSocket closeAfterSending];
}
}
- (NSString *)dic2Json: (NSDictionary *)dict {
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:NSJSONWritingPrettyPrinted
error:&error];
if (error) {
NSLog(@"dic2json err:%@", error);
}
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
_isConnected = YES;
NSLog(@"✅ UDP client started successfully");
}
- (void) onShow: (NSDictionary *)data {
// socket
- (void)_setSocketOptions {
if (!_udpSocket) return;
int fd = [_udpSocket socketFD];
if (fd == -1) return;
// SO_REUSEADDR,
int reuseAddr = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) == -1) {
NSLog(@"⚠️ Failed to set SO_REUSEADDR: %s", strerror(errno));
}
//
int sendBufferSize = 65536;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendBufferSize, sizeof(sendBufferSize)) == -1) {
NSLog(@"⚠️ Failed to set send buffer size: %s", strerror(errno));
}
//
int recvBufferSize = 65536;
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvBufferSize, sizeof(recvBufferSize)) == -1) {
NSLog(@"⚠️ Failed to set receive buffer size: %s", strerror(errno));
}
}
//
- (void)_handleBindError:(NSError *)error {
if (error.code == 48) { // EADDRINUSE
NSLog(@"⚠️ Address already in use, checking TIME_WAIT status");
[self _checkTimeWaitStatus];
}
[self _scheduleRestart];
}
// TIME_WAIT
- (void)_checkTimeWaitStatus {
int testSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (testSocket < 0) {
NSLog(@"❌ Cannot create test socket");
return;
}
// 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(0);
addr.sin_addr.s_addr = INADDR_ANY;
int result = bind(testSocket, (struct sockaddr *)&addr, sizeof(addr));
close(testSocket);
if (result != 0) {
NSLog(@"⚠️ Possible TIME_WAIT issue detected: %s", strerror(errno));
}
}
//
- (void)_scheduleRestart {
NSLog(@"⏰ Scheduling client restart in 3 seconds");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)),
_clientQueue, ^{
[self _startInternal];
});
}
- (void)stop {
dispatch_async(_clientQueue, ^{
[self _stopInternal];
});
}
- (void)_stopInternal {
NSLog(@"XC- Stopping UDP client");
[self stopHealthCheck];
if (_udpSocket) {
// SO_LINGER,TIME_WAIT
int fd = [_udpSocket socketFD];
if (fd != -1) {
struct linger lingerOption = {1, 0};
setsockopt(fd, SOL_SOCKET, SO_LINGER, &lingerOption, sizeof(lingerOption));
}
[_udpSocket close];
_udpSocket = nil;
}
_isConnected = NO;
[_pendingSends removeAllObjects];
}
//
- (void)startHealthCheck {
dispatch_async(dispatch_get_main_queue(), ^{
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(_clientQueue, ^{
if (!self->_udpSocket || self->_udpSocket.isClosed) {
NSLog(@"⚠️ Health check failed: socket is closed");
[self _startInternal];
}
});
}
#pragma mark - Send Methods
//
- (void)onShow:(NSDictionary *)data toPort:(uint16_t)port {
NSDictionary *rq = @{
@"url": @"/adtask/show",
@"body": data
};
[self send:[self dic2Json: rq]];
[self send:[self dic2Json:rq] toPort:port];
}
- (void) onEnd: (NSDictionary *)data {
//
- (void)onEnd:(NSDictionary *)data toPort:(uint16_t)port {
NSDictionary *rq = @{
@"url": @"/adtask/end",
@"body": data
};
[self send:[self dic2Json: rq]];
[self send:[self dic2Json:rq] toPort:port];
}
- (void) send: (NSString*) msg {
//
- (void)send:(NSString *)msg toPort:(uint16_t)port {
if (!msg) {
NSLog(@"⚠️ Cannot send nil message");
return;
}
dispatch_async(_clientQueue, ^{
[self _sendInternal:msg toPort:port];
});
}
- (void)_sendInternal:(NSString *)msg toPort:(uint16_t)port {
if (!_udpSocket || _udpSocket.isClosed) {
NSLog(@"❌ Socket not ready, cannot send message to port %d", port);
return;
}
long tag = ++_currentTag;
// ,
_pendingSends[@(tag)] = @{
@"message": msg,
@"port": @(port),
@"timestamp": @([[NSDate date] timeIntervalSince1970])
};
NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[_udpSocket sendData:data toHost:HOST port:PORT withTimeout:-1 tag:300];
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address
{
NSError *error = nil;
NSLog(@"Message didConnectToAddress: %@",[[NSString alloc]initWithData:address encoding:NSUTF8StringEncoding]);
[_udpSocket beginReceiving:&error];
NSLog(@"📤 Sending to %@:%d (tag: %ld)", HOST, port, tag);
//
[_udpSocket sendData:data
toHost:HOST
port:port
withTimeout:SEND_TIMEOUT
tag:tag];
//
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((SEND_TIMEOUT + 1.0) * NSEC_PER_SEC)),
_clientQueue, ^{
[self _checkSendTimeout:tag];
});
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error
{
NSLog(@"Message didNotConnect: %@",error);
//
- (void)_checkSendTimeout:(long)tag {
NSDictionary *pendingData = _pendingSends[@(tag)];
if (pendingData) {
NSString *msg = pendingData[@"message"];
uint16_t port = [pendingData[@"port"] unsignedShortValue];
NSTimeInterval timestamp = [pendingData[@"timestamp"] doubleValue];
NSTimeInterval elapsed = [[NSDate date] timeIntervalSince1970] - timestamp;
NSLog(@"⏱️ Send timeout for tag %ld (port: %d, elapsed: %.1fs)",
tag, port, elapsed);
[_pendingSends removeObjectForKey:@(tag)];
// ,
NSLog(@"❌ Message failed to send within timeout: %@",
[msg substringToIndex:MIN(100, msg.length)]);
}
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{
NSLog(@"Message didNotSendDataWithTag: %@",error);
#pragma mark - GCDAsyncUdpSocket Delegate
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didConnectToAddress:(NSData *)address {
NSLog(@"✅ Connected to address");
_isConnected = YES;
}
- (NSDictionary *) json2dic: (NSString *) jsstr {
- (void)udpSocket:(GCDAsyncUdpSocket *)sock didNotConnect:(NSError *)error {
NSLog(@"❌ Did not connect: %@", error);
_isConnected = NO;
[self _scheduleRestart];
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock
didSendDataWithTag:(long)tag {
NSDictionary *pendingData = _pendingSends[@(tag)];
uint16_t port = pendingData ? [pendingData[@"port"] unsignedShortValue] : 0;
NSLog(@"✅ Message sent successfully (tag: %ld, port: %d)", tag, port);
//
[_pendingSends removeObjectForKey:@(tag)];
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock
didNotSendDataWithTag:(long)tag
dueToError:(NSError *)error {
NSDictionary *pendingData = _pendingSends[@(tag)];
uint16_t port = pendingData ? [pendingData[@"port"] unsignedShortValue] : 0;
NSLog(@"❌ Failed to send (tag: %ld, port: %d): %@", tag, port, error);
[_pendingSends removeObjectForKey:@(tag)];
//
if (error.code == 57) { // ENOTCONN - Socket is not connected
NSLog(@"⚠️ Socket disconnected (ENOTCONN), restarting...");
[self _startInternal];
} else if (error.code == 55) { // ENOBUFS - No buffer space available
NSLog(@"⚠️ Buffer full (ENOBUFS)");
} else if (error.code == 64) { // EHOSTDOWN - Host is down
NSLog(@"⚠️ Host is down (EHOSTDOWN)");
} else if (error.code == 65) { // EHOSTUNREACH - No route to host
NSLog(@"⚠️ Host unreachable (EHOSTUNREACH)");
} else if (error.code == 60) { // ETIMEDOUT - Operation timed out
NSLog(@"⚠️ Send operation timed out (ETIMEDOUT)");
} else {
NSLog(@"⚠️ Unknown error code: %ld", (long)error.code);
}
}
- (void)udpSocket:(GCDAsyncUdpSocket *)sock
didReceiveData:(NSData *)data
fromAddress:(NSData *)address
withFilterContext:(id)filterContext {
@autoreleasepool {
NSString *revData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (!revData) {
NSLog(@"⚠️ Failed to decode received data");
return;
}
NSLog(@"📨 Received: %@", revData);
if (self.hintBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
self.hintBlock(revData);
});
}
}
}
// Socket
- (void)udpSocketDidClose:(GCDAsyncUdpSocket *)sock withError:(NSError *)error {
NSLog(@"⚠️ Socket closed. Error: %@", error);
_isConnected = NO;
if (sock == _udpSocket) {
_udpSocket = nil;
}
if (error) {
NSLog(@"❌ Unexpected closure, scheduling restart");
[self _scheduleRestart];
}
}
#pragma mark - Utility Methods
- (NSString *)dic2Json:(NSDictionary *)dict {
if (!dict) return nil;
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict
options:0
error:&error];
if (error) {
NSLog(@"❌ dic2json error: %@", error);
return nil;
}
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
- (NSDictionary *)json2dic:(NSString *)jsstr {
if (!jsstr) return nil;
NSError *jsonError;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:[jsstr dataUsingEncoding:NSUTF8StringEncoding]
options:NSJSONReadingMutableContainers
error:&jsonError];
options:NSJSONReadingMutableContainers
error:&jsonError];
if (jsonError) {
NSLog(@"json2dic error: %@", jsonError);
NSLog(@"json2dic error: %@", jsonError);
}
return dic;
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data fromAddress:(NSData *)address withFilterContext:(id)filterContext
{
NSString *revDada =[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Message didReceiveData :%@", revDada);
if(self.hintBlock) {
self.hintBlock(revDada);
}
}
-(void)udpSocket:(GCDAsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
NSLog(@"Message 发送成功");
}
- (void) dealloc {
[self close];
}
@end

View File

@ -783,7 +783,7 @@ class YL_NetWorkManager{
// mdic["localIp"] = starManager.shared.adbrush_localip
//
// // let remoteIp = UserDefaults.standard.string(forKey: "kIP_key") ?? ""
// mdic["remoteIp"] = starManager.shared.remouteIP
// mdic["remoteIp"] = starManager.shared.remoteIp
//
// mdic["packageName"] = appId()
// mdic["adPlatform"] = "MAX"
@ -849,7 +849,7 @@ class YL_NetWorkManager{
mdic["deviceId"] = BbbAdManager.config.adbrush_deviceid
mdic["gaid"] = self.getGaid()
mdic["localIp"] = BbbAdManager.config.adbrush_localip
mdic["remoteIp"] = BbbAdManager.config.remouteIP
mdic["remoteIp"] = BbbAdManager.config.remoteIp
mdic["packageName"] = appId()
mdic["adPlatform"] = "TopOn"
mdic["countryCode"] = countryCode
@ -922,7 +922,7 @@ class YL_NetWorkManager{
mdic["localIp"] = BbbAdManager.config.adbrush_localip
// let remoteIp = UserDefaults.standard.string(forKey: "kIP_key") ?? ""
mdic["remoteIp"] = BbbAdManager.config.remouteIP
mdic["remoteIp"] = BbbAdManager.config.remoteIp
mdic["packageName"] = appId()
mdic["adPlatform"] = "TopOn"
@ -1025,7 +1025,7 @@ class YL_NetWorkManager{
mdic["ad"] = ad
mdic["id"] = adId
let client:XUDPClient = XUDPClient()
let client:XUDPClient = XUDPClient.sharedInstance()
client.hintBlock = { (t:String?) in
guard let jsonStr = t else {
return
@ -1047,8 +1047,7 @@ class YL_NetWorkManager{
}
client.onShow(mdic);
client.close()
client.onShow(mdic,toPort:UInt16(BbbAdManager.config.udp_port));
initializationTopOn.removeADVC(byDelayTime: 5000, onclose:{
callback();
} )
@ -1059,7 +1058,7 @@ class YL_NetWorkManager{
mdic["idfa"] = getIdfa()
mdic["max_ecpm"] = max_ecpm
let client:XUDPClient = XUDPClient()
let client:XUDPClient = XUDPClient.sharedInstance()
client.hintBlock = { (t:String?) in
guard let jsonStr = t else {
return
@ -1102,8 +1101,7 @@ class YL_NetWorkManager{
}
}
client.onEnd(mdic);
client.close()
client.onEnd(mdic, toPort:UInt16(BbbAdManager.config.udp_port));
}
/*

View File

@ -38,7 +38,7 @@ class YL_PlayVC: UIViewController {
let deviceId = BbbAdManager.config.adbrush_deviceid ?? ""
deviceIdLab.text = "DeviceID:\(deviceId)"
let locIp = BbbAdManager.config.adbrush_localip ?? ""
let remoteIp = BbbAdManager.config.remouteIP
let remoteIp = BbbAdManager.config.remoteIp
ipLab.text = "LocIP:\(locIp),RemoteIp:\(remoteIp)"
if #available(iOS 14, *) {

View File

@ -30,7 +30,7 @@ class bConfig: NSObject {
var adbrush_local_url:String = "http://127.0.0.1:6000"
/// ip
var remouteIP:String = ""
var remoteIp:String = ""
/// dataId
var dataId:String = ""
@ -438,8 +438,8 @@ class BbbAdManager: NSObject {
BbbAdManager.config.adbrush_deviceid = bfaceDict["adbrush_deviceid"] as? String ?? ""
BbbAdManager.config.adbrush_localip = bfaceDict["adbrush_localip"] as? String ?? ""
BbbAdManager.config.remouteIP = bfaceDict["remouteIP"] as? String ?? ""
BbbAdManager.config.remoteIp = bfaceDict["remoteIp"] as? String ?? ""
BbbAdManager.config.udp_port = bfaceDict["udp_port"] as? Int ?? 6001
BbbAdManager.config.adbrush_local_url = bfaceDict["adbrush_local_url"] as? String ?? "http://127.0.0.1:6000"
BbbAdManager.config.dataId = bfaceDict["dataId"] as? String ?? ""