Стандартный метод отправки данных в потоковый сокет всегда состоял в том, чтобы вызвать 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 () обычно блокирует ...
Что означает, что мы должны предполагать, что отправка может вернуться без отправки всех данных. Сейчас я нахожу это несколько неработающим, но даже У. Ричард Стивенс допускает это в своем стандартном справочнике о сетевом программировании , не в первых главах, но в более сложных примерах используется его собственная функция write (write all data) вместо звонка пишите.
Теперь я считаю, что это все еще более или менее нарушено, поскольку если send не может передать все данные или принять данные в базовом буфере, а сокет блокируется, тогда send должен блокироваться и возвращаться, когда весь запрос send был принят.
Я имею в виду, что в приведенном выше примере кода, что произойдет, если при отправке возвращается с меньшим количеством отправленных данных, это будет вызвано снова с новым запросом. Что изменилось с момента последнего звонка? Максимально прошло несколько сотен циклов ЦП, поэтому буфер все еще заполнен. Если send now принимает данные, почему не может принять их раньше?
В противном случае мы закончим upp неэффективным циклом, в котором мы пытаемся отправлять данные в сокет, который не может принимать данные и продолжать попытки, или иначе?
Таким образом, кажется, что обходной путь, если необходимо, приводит к крайне неэффективному коду, и в этих обстоятельствах следует избегать блокирующих сокетов вообще, вместо этого следует использовать неблокирующие сокеты вместе с select.