#objective-c #ios #titanium #nsdata #titanium-modules
#objective-c #iOS #titanium #nsdata #titanium-модули
Вопрос:
Я новичок в Objective C и модифицирую модуль iOS для платформы Titanium, который отправляет UDP-пакеты. В настоящее время модуль позволяет передавать текстовую строку для отправки, преобразует ее в байты и отправляет через UDP на IP-адрес назначения и порт. Это отлично работает, и вот код:
https://github.com/chrisfjones/titanium_module_udp/blob/master/UDPSocketProxy.m
Что я хочу сделать, это передать массив байтов в функцию отправки вместо строки и просто отправить ее. Вот код Titanium:
var udp = require('chrisfjones.titanium_module_udp');
var socket = udp.createUDP();
var bytes = [ 100, 15, 132, 53, 14, 246, 0, 0, 0, 0, 196, 209, 1, 1, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 16, 0, 45, 120, 0, 0, 0, 0, 158, 4, 111, 30, 179, 41 ];
socket.send(bytes, "1.2.3.4", 6100);
И вот новая функция отправки до сих пор:
- (void) sendBytes: (NSArray*) args {
NSArray *msg = (NSArray*)[args objectAtIndex: 0];
NSString *host = [TiUtils stringValue:[args objectAtIndex: 1]];
NSInteger port = [TiUtils intValue: [args objectAtIndex: 2]];
NSLog(@"%@ send bytes: %@ to %@:%i", self, msg, host, port);
struct sockaddr_in destinationAddress;
socklen_t sockaddr_destaddr_len = sizeof(destinationAddress);
memset(amp;destinationAddress, 0, sockaddr_destaddr_len);
destinationAddress.sin_len = (__uint8_t) sockaddr_destaddr_len;
destinationAddress.sin_family = AF_INET;
destinationAddress.sin_port = htons(port);
destinationAddress.sin_addr.s_addr = inet_addr([host cStringUsingEncoding: NSUTF8StringEncoding]);
NSData *destinationAddressData = [NSData dataWithBytes:amp;destinationAddress length:sizeof(destinationAddress)];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:msg];
CFSocketError socket_error = CFSocketSendData(_socket, (CFDataRef) destinationAddressData, (CFDataRef) data, 10);
if (socket_error) {
NSLog(@"socket error: %li", socket_error);
} else {
NSLog(@"sent bytes: '%@' to %@:%i", msg, host, port);
}
}
Вы заметите, что он передается в NSArray. Это потому, что Titanium преобразует созданный мной массив javascript в NSArray объектов NSNumber. Я читал, что это ужасно неэффективно, но оно встроено в платформу Titanium, поэтому я не вижу способа обойти это, поэтому я надеюсь на ответ о том, как заставить его работать с передачей этого, а не на лекцию о том, насколько это неэффективно.
Когда я вызываю новый метод отправки, вместо того, чтобы отправлять около 50 байт, которые я передаю, я вижу в wireshark, что он фактически передает более 1000 байт. Я предполагаю, что проблема связана с преобразованием в этой строке:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:msg];
Может кто-нибудь, пожалуйста, помочь в том, как просто отправить массив байтов, который я передаю? Спасибо!
Ответ №1:
Да, вы не хотите использовать архиватор в этом случае, поскольку вы просто пытаетесь превратить набор байтов в блок NSData
. В зависимости от того, передаете ли вы массив NSNumber
или массив NSString
, вам в основном нужно будет перебирать содержимое массива и добавлять данные в an NSMutableData
.
Предполагая, что это массив NSNumber
, тогда должно сработать что-то вроде этого:
NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [msg count]];
for( NSNumber *number in msg) {
char byte = [number charValue];
[data appendBytes: amp;byte length: 1];
}
// .... code that uses data ...
[data release];
Если числа представляют собой числовые значения в строковой форме, вы, вероятно, захотите использовать -(int)intValue
метод NSString
для извлечения данных, а затем добавить их к данным, в основном изменив приведенное выше на:
NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [msg count]];
for( NSString *string in msg) {
char byte = (char)[string intValue];
[data appendBytes: amp;byte length: 1];
}
// .... code that uses data ...
[data release];
И, если вы пытаетесь вставить символы из строк, вам нужно будет использовать символ [string characterAtIndex: 0]
и компенсировать тот факт, что вы будете получать a unichar
вместо a char
.
Комментарии:
1. Отлично работает, спасибо! Одно небольшое изменение: «аргументы» в первой и второй строках должны быть «msg».
Ответ №2:
- (NSData *)byteArray2Data:(NSArray *)array {
NSMutableData *data = [NSMutableData data];
[array enumerateObjectsUsingBlock:^(NSNumber* number, NSUInteger index, BOOL* stop) {
uint8_t tmp = number.unsignedCharValue;
[data appendBytes:(void *)(amp;tmp)length:1];
}];
return data;
}
- (NSArray *)byteData2Array:(NSData *)data {
NSMutableArray *array = [[NSMutableArray alloc] init];
[data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
unsigned char *dataBytes = (unsigned char*)bytes;
for (NSInteger i = 0; i < byteRange.length; i ) {
[array addObject:[NSNumber numberWithInt:(dataBytes[i]) amp; 0xff]];
}
}];
return array;
}