Простой posix-сервер не может установить UILabel из цикла

Я пытаюсь добавить сервер сокетов posix в свое приложение для iOS, которое разрешит TCP-соединение и записывает буфер в объект UILabel в качестве теста.

Я могу заставить его работать... один раз. Затем он завершает и закрывает соединение. Хорошо, легко исправить, я просто поставлю это в цикл. Теперь всякий раз, когда я помещаю один и тот же код в цикл, он по какой-то причине не обновляет UILabel. На самом деле мне не нужно обновлять UILabel, это был просто тест, чтобы убедиться, что сервер работает ...... но это заставляет меня нервничать. Я вынимаю его из цикла while, он работает, я вставляю его обратно, и работает все, кроме вызова UILabel setText.

Кроме того, два других небольших вопроса: мне трудно понять, как выйти из цикла после отключения клиента, и я не уверен, как правильно закрыть порты при выходе, я должен постоянно менять номер порта, потому что это не могу связать.

-(void)viewDidLoad

    NSThread *listenThread = [[NSThread alloc] initWithTarget:self selector:@selector(createPosixServer) object:nil];
    [listenThread start];

-(void)создатьPosixServer

    //declarations
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    NSString *nsbuffer;

    //bind and listen on socket
    sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (sockfd < 0) {
        NSLog(@"Error while calling socket()");
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = 1818;
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
        NSLog(@"ERROR on binding");
    }
    listen(sockfd, 5);
    NSLog(@"Begin listen loop");
    clilen = sizeof(cli_addr);
    newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
    if (newsockfd < 0) {
        NSLog(@"ERROR on accept");
    }
    while(true) {
        bzero(buffer,256);

        n = read(newsockfd,buffer,255);
        if (n < 0) {
            NSLog(@"ERROR reading from socket");

        }
        if (n > 0) {
            nsbuffer = [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding];
            [_lblStatus setText:nsbuffer];
            NSLog(@"You sent %@", nsbuffer);
        }

        NSLog(@"Finished listen loop");
        sleep(1);
    }
    close(newsockfd);
    close(sockfd);
    NSLog(@"Socket closed");

person jamzsabb    schedule 01.09.2015    source источник
comment
Вчера забыл включить код. Был действительно жареным после долгого дня программирования!   -  person jamzsabb    schedule 03.09.2015


Ответы (1)


createPosixServer работает в фоновом потоке. Никогда не бывает безопасно обновлять пользовательский интерфейс из фонового потока. UIKit иногда работает, иногда просто игнорирует вас. Вам нужно отправить вызов для обновления метки в основной поток, примерно так:

typeof(self) __weak weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    weakSelf.lblStatus.text = nsbuffer;
});

Чтобы ответить на побочный вопрос: когда клиент отключается, вы хотите закрыть сокет, который вы приняли для этого соединения (ваш newsockfd), но вы не хотите закрывать своего слушателя sockfd, пока не отключите всю службу.

Чтобы выйти из цикла, просто сделайте следующее:

if (n < 0) {
    NSLog(@"ERROR reading from socket");
    break;
}

Хотя вы, вероятно, захотите также проверить errno в этом блоке, потому что вам, вероятно, потребуется другое поведение в зависимости от ошибки.

Удалите sleep(1), это вам не поможет. Звонок read заблокируется, спать не надо.

person Ewan Mellor    schedule 03.09.2015
comment
Ах, спасибо! Я подозревал, что обновлять пользовательский интерфейс из отдельного потока нельзя, но я не был уверен, как смешать C и Objective-C, чтобы сделать вызов правильно. И я закрывал его назад, похоже, я думал, что объект sockfd будет первым, так как я создал его последним. Мне никогда не приходило в голову, что именно этой части мне не хватало. А что вы имели в виду, что вызов read() заблокирует? Вызов sleep() должен был убедиться, что я не перегружаю процессор, проверяя его миллион раз в секунду. Мне это совсем не нужно? - person jamzsabb; 04.09.2015