Стандартный метод отправки данных в сокет потока всегда заключался в вызове send с фрагментом данных для записи, проверке возвращаемого значения, чтобы увидеть, все ли данные были отправлены, а затем продолжать вызывать send снова, пока все сообщение не будет принято.
Например, это простой пример общей схемы:
int send_all(int sock, unsigned char *buffer, int len) { int nsent; while(len > 0) { nsent = send(sock, buffer, len, 0); if(nsent == -1) // error return -1; buffer += nsent; len -= nsent; } return 0; // ok, all data sent }
Даже в справочной странице BSD упоминается, что
... Если в сокете нет свободного места для сообщений для хранения передаваемого сообщения, то send () обычно блокируется ...
Это означает, что мы должны предположить, что send может вернуться без отправки всех данных. Сейчас я нахожу это довольно неуместным, но даже У. Ричард Стивенс предполагает это в своем стандартном справочнике по сетевому программированию, не в первых главах, но в более сложных примерах вместо вызова write используется его собственная функция Writen (запись всех данных).
Теперь я считаю, что это все еще более или менее нарушено, поскольку, если send не может передать все данные или принять данные в базовом буфере, а сокет блокируется, тогда send должен блокироваться и возвращаться, когда весь запрос отправки был принят. .
Я имею в виду, что в приведенном выше примере кода, что произойдет, если send вернется с меньшим количеством отправленных данных, так это то, что он будет вызываться снова с новым запросом. Что изменилось с момента последнего звонка? Прошло не более нескольких сотен циклов ЦП, поэтому буфер все еще заполнен. Если send now принимает данные, почему он не мог их принять раньше?
В противном случае мы закончим upp неэффективным циклом, в котором мы пытаемся отправить данные в сокет, который не может принимать данные, и продолжаем попытки, иначе?
Таким образом, кажется, что обходной путь, если необходимо, приводит к сильно неэффективному коду, и в этих обстоятельствах следует избегать блокировки сокетов вообще, вместо этого следует использовать неблокирующие сокеты вместе с select.