Позволяет переформатировать ваш цикл while
, чтобы его было легче читать:
while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN)
{
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
}
}
else if (fds[0].revents & POLLOUT)
{
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}
Теперь должно быть понятно, почему ваш блок POLLOUT
никогда не выполняется - этот оператор if
достигается только тогда, когдаpoll()
возвращает <= 0
, что не то, что вам нужно.
Вместо этого вам нужна такая логика:
while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN )
{
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
}
else if (fds[0].revents & POLLOUT)
{
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}
}
, которая при переформатировании обратно в исходный стиль кодированияВыглядит так:
while (true) {
if ((rv = poll(fds, 1, 100) > 0)) {
if (fds[0].revents & POLLIN ){
recv(sockfd, buff, 200, 0);
printf("From Server : %s", buff);
bzero(buff, sizeof(buff));
} else if (fds[0].revents & POLLOUT){
puts(buff);
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, sizeof(buff));
break;
}
}
}
Видите разницу, которую делает хорошее форматирование?
При этом знайте, что сокет входит в состояние записи, как только он подключается.Таким образом, ваш код, скорее всего, отправит приветствие клиента, прежде чем ждать приветствия сервера.Если вам нужно дождаться приветствия сервера перед ответом, вам нужно сначала прочитать приветствие, например:
while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN)
{
rv = recv(sockfd, buff, 200, 0);
if (rv <= 0) break;
printf("From Server : %.*s", rv, buff);
if (/* the complete greeting has been read */) // MAY take multiple reads!
{
strcpy(buff, "HELLO WORLD");
write(sockfd, buff, strlen(buff));
break;
}
}
}
}
Обратите внимание, что при использовании блокирующих сокетов необязательно обрабатывать POLLOUT
.Но если вместо этого вы используете неблокирующие сокеты, вы несете ответственность за проверку, если write()
завершается с ошибкой EWOULDBLOCK
, и если это так, тогда буферизируйте данные, которые вы пытались отправить, которые не удалось, а также любые последующие данные доСообщается POLLOUT
, затем вы можете отправлять буферизованные данные (продолжая обрабатывать EWOULDBLOCK
и POLLOUT
), пока буфер не будет пуст.Только после этого вы можете отправлять новые данные через сокет, не обрабатывая POLLOUT
снова, пока не появится новая ошибка EWOULDBLOCK
.Например:
int sendData(int fd, void *data, int len)
{
char *pdata = (char *) buff;
if (/* fd's buffer is empty */)
{
while (len > 0)
{
int rv = send(fd, pdata, len, 0);
if (rv < 0)
{
if (errno != EWOULDBLOCK)
return rv;
break;
}
pdata += rv;
len -= rv;
}
}
if (len > 0)
{
// add pdata up to len bytes to fd's buffer...
}
return 0;
}
...
while (true)
{
if ((rv = poll(fds, 1, 100) > 0))
{
if (fds[0].revents & POLLIN)
{
rv = recv(sockfd, buff, 200, 0);
if (rv <= 0) break;
printf("From Server : %.*s", rv, buff);
if (/* the complete greeting has been read */) // MAY take multiple reads!
{
strcpy(buff, "HELLO WORLD");
sendData(sockfd, buff, strlen(buff));
}
}
if (fds[0].revents & POLLOUT)
{
char *pdata = ...; // fd's buffer data
int len = ...; // fd's buffer length
int sent = 0;
while (len > 0)
{
rv = send(fd, pdata, len, 0);
if (rv < 0)
break;
pdata += rv;
len -= rv;
sent += rv;
}
if (sent > 0)
{
// remove sent bytes from fd's buffer...
}
}
}
}
Затем вы можете использовать sendData()
в любое время, когда вам нужно отправить какие-либо данные на fd
, вместо прямого вызова write()
/ send()
.