Сервер / Клиент не взаимодействует правильно (CocoaAsyncSocket)
У меня есть простое клиент-серверное приложение, частично работающее с CocoaAsyncSocket. Я могу использовать клиент для подключения к серверу, и могу передавать данные туда и обратно между ними, и методы делегата, кажется, работают правильно. Моя проблема в том, что я могу отправлять данные только объекту (AsyncSocket *), который передается одному из методов делегата. Принимая соединение, я добавляю сокет в NSMutableArray, но позже, если я пытаюсь использовать сокет, запись не выполняется. Так
[connectedSockets addObject:newSocket];
//then later
[[connectedSockets objectAtIndex:i] writeData:someData withTimeout:-1 tag:0];
не работает Код ниже для сервера и клиента. Первоначальная связь работает, но когда вызывается мое уведомление, никакие данные не отправляются, даже несмотря на то, что оператор NSLog проверяет сокет в массиве и получает правильный IP-адрес и номер порта:
Сервер:
- (id)init
{
self = [super init];
if (self) {
listenSocket = [[AsyncSocket alloc] initWithDelegate:self];
[listenSocket setRunLoopModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
[listenSocket acceptOnPort:42381 error:nil];
connectedSockets = [[NSMutableArray alloc] init];
newNotificationDictArray = [[NSMutableArray alloc] init];
updateNotificationDictArray = [[NSMutableArray alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(newJobNotification:)
name:@"NewJob"
object:nil];
}
return self;
}
-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
[connectedSockets removeObject:sock];
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
[connectedSockets removeObject:sock];
}
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
[connectedSockets addObject:newSocket];
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
if ([newNotificationDictArray count] > 0) {
NSMutableData *data = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[archiver encodeObject:newNotificationDictArray forKey:@"DictArray"];
[archiver finishEncoding];
[archiver release];
[sock writeData:data withTimeout:-1 tag:0];
[data release];
}
[sock readDataWithTimeout:-1 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
[sock readDataWithTimeout:-1 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
[sock readDataWithTimeout:-1 tag:0];
}
-(void) newJobNotification: (NSNotification *) notification
{
NSDictionary *dict = [notification userInfo];
[newNotificationDictArray addObject:dict];
[updateNotificationDictArray addObject:dict];
NSMutableData *updateData = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:updateData];
[archiver encodeObject:updateNotificationDictArray forKey:@"DictArray"];
[archiver finishEncoding]
[updateNotificationDictArray removeAllObjects];
[archiver release];
NSLog(@"Attempting to write to %@:%i", [[connectedSockets objectAtIndex:0] connectedHost], [[connectedSockets objectAtIndex:0] connectedPort])
[[connectedSockets objectAtIndex:0] writeData:updateData withTimeout:-1 tag:0];
}
а потом клиент:
- (id)init
{
self = [super init];
if (self) {
socket = [[AsyncSocket alloc] initWithDelegate:self];
}
return self;
}
-(void) connectToHost: (NSString *) address
{
}
-(BOOL)onSocketWillConnect:(AsyncSocket *)sock
{
[sock retain];
[socket readDataWithTimeout:-1 tag:0];
return YES;
}
-(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(@"Did Connect on port %i", [sock connectedPort]);
}
-(void) disconnectFromRemoteHost
{
[socket disconnect];
}
-(void)onSocketDidDisconnect:(AsyncSocket *)sock
{
NSLog(@"Did Disconnect");
}
- (void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err
{
NSLog(@"Disconnect Error: %@", [err localizedDescription]);
}
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
[socket readDataWithTimeout:-1 tag:0];
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
NSArray *dictArray = [[unarchiver decodeObjectForKey:@"DictArray"] retain];
[unarchiver finishDecoding];
[unarchiver release];
for (NSDictionary *dict in dictArray) {
if ([[dict objectForKey:@"Kind"] isEqualTo:@"New"])
[[NSNotificationCenter defaultCenter] postNotificationName:@"NewJob" object:self userInfo:dict];
else if ([[dict objectForKey:@"Kind"] isEqualTo:@"Update"])
[[NSNotificationCenter defaultCenter] postNotificationName:@"JobUpdate" object:self userInfo:dict];
}
[socket readDataWithTimeout:-1 tag:0];
}
Помоги мне stackru, ты моя единственная надежда!
1 ответ
Я вижу 2 потенциальных проблемы с вашим размещенным кодом. Первое, кажется, вряд ли вызывает ваши проблемы, но я все равно выложу. В вашем коде клиента у вас есть:
-(BOOL)onSocketWillConnect:(AsyncSocket *)sock
{
[sock retain];
[socket readDataWithTimeout:-1 tag:0];
return YES;
}
Я не уверен, почему вы сохранили "носок" здесь. У вас уже есть сохраненная копия сокета, который вы создали, и это может привести к утечке.
Что касается второй проблемы, которая, скорее всего, станет причиной ваших неудач, я думаю, что это происходит. Глядя на документацию по AsyncSocket, я вижу это:
Однако AsyncSocket не является потокобезопасным. Вы должны вызывать методы в AsyncSocket только из потока / runloop, на котором настроен сокет. Если вы оказались в потоке, который отличается от потока, в котором запущен AsyncSocket, и вам нужно вызвать метод в AsyncSocket, то вы должны использовать метод, подобный executeSelector: onThread: чтобы убедиться, что метод вызывается из потока AsyncSocket (и тем самым поддерживая безопасность потока).
Ваш код, который получает уведомления и запускает "более позднюю" запись, вероятно, находится в другом потоке, поэтому даже через этот поток запись не выполняется, как вы ожидаете. Далее в документации AsyncSocket предлагается использовать GCDAsyncSocket, если вы хотите обеспечить безопасность потоков.