Раньше пользовался WinAPI, и оттуда функциями WSASend и WSAGetOverlappedResult. Теперь тоже самое нужно реализовать силами POSIX: socket, send и т.п. У меня сокет НЕ блокируемый, поэтому вызов send(), как я думаю, вернёт -1 и номер ошибки в <errno>, которым могут быть EAGAIN или EWOULDBLOCK (проверить пока не могу, так что извините). После этого, можно ждать, пока сокет будет доступен на запись (соответственно, если доступен на запись, то данные (прошлые) ушли и можно писать заного). Но! Мне нужно узнать, сколько реально байт данных ушло, т.к. send() может отправить не то кол-во данных, которое ему подсовываешь :-( Пока набросал такой код: Код (Text): switch (errno) { case EWOULDBLOCK: while (1) { tv.tv_sec = timeout; /* мой таймаут */ tv.tv_usec = 0; /* ждать, пока сокет будет доступен на запись */ FD_ZERO (&writefds); FD_SET (priv->socket, &writefds); rc = select (priv->socket+1, NULL, &writefds, NULL, &tv); if (rc < 0) { /* ошибка в select() */ return 1; } else if (rc==0) { /* таймаут - продолжать ждать, но уже новым select() */ continue; } else if (rc > 0) { /* сокет доступен на запись, видимо, данные ушли */ /* ЗДЕСЬ нужно определить, сколько байт реально ушло :-) */ break; } } break;
А зачем тебе знать, сколько байт? Если есть EAGAIN, значит, надо переслать заново. Если есть ошибка при отправке - не прошло. Если ни то ни другое - все байты ушли. Точнее скорее всего байты перенеслись в некий буфер, функция возвратила управление, а система в фоне выслала все данные. Если select сообщает, что можно писать, значит все ушло. На тот случай, если твоих данных слишком много, вот что говорит man: If the message is too long to pass atomically through the underlying protocol, the error EMSGSIZE is returned, and the message is not transmitted. P.S. Очень рекомендую задавать подобные вопросы на www.opennet.ru
Вот здесь: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#sendall автор пишет, что данные могут уйти не все: Поэтому и спрашиваю о том, что делать если не все данные ушли :-(
Искал по инэту, в общем, пришёл к выводу: send() всегда блокирует, даже если сокет НЕ блокируемый. Результат EAGAIN означает, что нужно повторить попытку отправки, а не, как я думал, то, что нужно подождать отправки данных, как это делается с WSASend. Или я чего-то фундаментального не понимаю, или WSASend и send работают кардинально по-разному: одна адаптирована для не блокируемых операций, другая не адаптирована. Всем спасибо.
У тебя кстати в примере и есть блокирующий код =) Даже если send не блокируется, твоя прога блокируется, так как ждет в цикле. Если твоя прога - это сервер, то я обычно делал так. Открываю на прослушку неблокируемый сокет, принимаю соединения. При коннекте клиента создается сокет общения с клиентом (дочерний). В итоге их целый массив собирается. Все дочерние сокеты - блокируемые. Все сокеты (включая главный) загоняются в fdset и передаются в select. При событии на главном сокете: if(FD_ISSET(sock, &fdset_r) || FD_ISSET(sock, &fdset_w)) означает, что новое соединение. Обрабатываем его, добавляем новый сокет в массив. При событии на дочерних: for(map<int, client_info> ::iterator Iter = map_clients.begin(), End = map_clients.end(); Iter != End; Iter++){ int sclient = Iter->first; if(FD_ISSET(sclient, &fdset_r)){....} .... } Обрабатывается ввод - вывод с дочерними сокетами в блокирующем режиме. Ничего обычно не виснет, так как сокет уже готов на ввод-вывод. (Тока вместо массива использовался std::map в этом коде)
AlannY Почему? Если send обнаружит, что может заблокировать неблокируйщий сокет, то он возвращает -1, а в errno будет записано EAGAIN или EWOULDBLOCK. В случае если send что-то отправил, то количество реально отправленных байт он вернет. При том реально может быть отправлено меньше байт, чем было передано в качестве параметров. http://www.opennet.ru/man.shtml?topic=send&category=2&russian=0