Мы пишем клиент и сервер, чтобы делать (что я думал) довольно простые сетевые коммуникации. Клиенты Mulitple подключаются к серверу, который затем должен отправлять данные всем остальным клиентам.читайте и пишите в тот же сокет (TCP), используя select
Сервер просто сидит в блокирующей петле select
, ожидая трафика, а когда приходит, отправляет данные другим клиентам. Кажется, это работает отлично.
Проблема заключается в клиенте. В ответ на чтение он иногда хочет писать.
Однако, я обнаружил, что если я использую:
rv = select(fdmax + 1, &master_list, NULL, NULL, NULL);
Мой код будет блокироваться, пока нет новых данных для чтения. Но иногда (асинхронно, из другого потока) у меня будут новые данные для записи в потоке сетевой связи. Итак, я хочу, чтобы мои выбрать просыпаться периодически, и позвольте мне проверить, есть ли данные писать, как:
if (select(....) != -1)
{
if (FD_SET(sockfd, &master_list))
// handle data or disconnect
else
// look for data to write and write()/send() those.
}
Я попытался установить выберите режим (или смехотворно короткий таймаут) с опросом:
// master list contains the sockfd from the getaddrinfo/socket/connect seq
struct timeval t;
memset(&t, 0, sizeof t);
rv = select(fdmax + 1, &master_list, NULL, NULL, &t);
но обнаружили, что тогда клиент никогда не получает никаких входящих данных.
Я также попытался установить гнездо FD быть неблокирующая, как:
fcntl(sockfd, F_SETFL, O_NONBLOCK);
, но это не решает проблему:
- если мой клиент
select()
не имеетstruct timeval
, чтение данные работают, но он никогда не разблокирует, чтобы позволить мне искать доступные для записи данные. - Если у моего клиента
select()
естьtimeval
, чтобы получить его для опроса, то он никогда не сигнализирует о том, что есть данные для чтения, и мое приложение замерзает, думая, что нет сетевого подключения (несмотря на то, что все остальные вызовы функций преуспели)
Любые указания на то, что я могу делать неправильно? Невозможно выполнить чтение-запись в одном сокете (я не могу поверить, что это правда).
(EDIT: Правильный ответ, и то, что я запомнил на сервере, но не на клиенте, чтобы иметь второй fd_set и скопировать master_list перед каждым вызовом, чтобы выбрать():
// declare and FD_ZERO read_fds:
// put sockfd in master_list
while (1)
{
read_fds = master_list;
select(...);
if (FD_ISSET(read_fds))
....
else
// sleep or otherwise don't hog cpu resources
}
)
извините, что если (FD_SET (... должно быть, если (FD_ISSET (.... – MarcWan