C-Unix Sockets - Неблокирующее чтение - PullRequest
5 голосов
/ 13 ноября 2011

Я пытаюсь сделать простую клиент-серверную программу чата.На стороне клиента я раскручиваю другой поток, чтобы прочитать любые поступающие данные с сервера.Проблема в том, что я хочу аккуратно прекратить этот второй поток, когда человек выходит из основного потока.Я пытался использовать разделяемую переменную 'running' для завершения, проблема в том, что команда socket read () является командой блокировки, поэтому, если я делаю в то время как (running == 1), сервер должен что-то отправить до того, как чтение вернетсяи условие while может быть проверено снова.Я ищу метод (только с обычными сокетами Unix) для выполнения неблокирующего чтения, в основном, будет работать некоторая форма peek (), поскольку я могу постоянно проверять цикл, чтобы убедиться, что я закончил.

Цикл потока чтения находится ниже, сейчас у него нет мьютекса для общих переменных, но я планирую добавить, что позже не волнуйтесь!;)

void *serverlisten(void *vargp)
{
    while(running == 1)
    {
        read(socket, readbuffer, sizeof(readbuffer));
        printf("CLIENT RECIEVED: %s\n", readbuffer);
    }
    pthread_exit(NULL);
}

Ответы [ 5 ]

8 голосов
/ 13 ноября 2011

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

fd_set         input;
FD_ZERO(&input);
FD_SET(sd, &input);
struct timeval timeout;
timeout.tv_sec  = sec;
timeout.tv_usec = msec * 1000;
int n = select(sd + 1, &input, NULL, NULL, &timeout);
if (n == -1) {
    //something wrong
} else if (n == 0)
    continue;//timeout
if (!FD_ISSET(sd, &input))
   ;//again something wrong
//here we can call not blockable read
7 голосов
/ 13 ноября 2011
fcntl(socket, F_SETFL, O_NONBLOCK);

или, если у вас есть другие флаги:

int x;
x=fcntl(socket ,F_GETFL, 0);
fcntl(socket, F_SETFL, x | O_NONBLOCK);

затем проверьте возвращаемое значение read, чтобы увидеть, были ли доступны данные.

примечание: немного прибегнув к поиску, вы получите множество полных примеров.

Вы также можете использовать блокирующие сокеты и «peek» с select с таймаутом. Здесь это кажется более уместным, поэтому вы не заняты ожиданием.

2 голосов
/ 13 ноября 2011

Лучше всего избавиться от лишней нити и использовать select() или poll() для обработки всего в одной нити.

Если вы хотите сохранить поток, одну вещь, которую вы можете сделать, это вызвать shutdown() в сокете с SHUT_RDWR, что отключит соединение, разбудит все блокированные на нем потоки, но сохранит действительный дескриптор файла. После того, как вы присоединились к теме чтения, вы можете закрыть сокет. Обратите внимание, что это работает только для сокетов, но не для файловых дескрипторов других типов.

1 голос
/ 13 ноября 2011

Ищите функцию setsockopt с опцией SO_RCVTIMEO.

0 голосов
/ 13 ноября 2011

Это может быть не тот конкретный ответ, который вы ищете, но это может быть место, где вы могли бы его найти.Я сейчас читаю:

Сетевое программирование Unix, Том 1: API-интерфейс для сокетов, 3-е издание

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

Надеюсь, что это поможет ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...