¿Por qué los datos enviados y recibidos por sockets sin bloqueo son inconsistentes?
Lo primero que hay que tener en cuenta es que los datos se copian del búfer de la aplicación al búfer del kernel cuando se envían, ya sea con o sin bloqueo (se declara la opción SO_RCVBUF, a menos que el tamaño del búfer sea 0). Vi a alguien en Internet decir que bloquear significa enviar datos a la otra parte. El bloqueo ocurre cuando todos los datos anteriores deben enviarse antes de enviarse esta vez. No bloquear significa copiar al búfer de envío. Debo decir que la afirmación anterior es incorrecta.
En el modo de bloqueo, la operación de envío esperará a que todos los datos se copien en el búfer de envío antes de regresar.
Si el tamaño total actual del búfer de envío es 8192, los datos que se han copiado al búfer son 8000 y el tamaño restante es 192, y ahora es necesario enviar 2000 bytes de datos, entonces el envío bloqueado esperará a que se copie el búfer. Los 2000 bytes de datos, por ejemplo, se copiaron a 192 bytes por primera vez, el búfer envió con éxito 1800 bytes.
No es difícil ver en el proceso anterior que el tamaño de envío devuelto por la operación de envío de bloqueo debe ser la longitud de envío en sus parámetros.
La operación de envío a en modo de bloqueo no se bloqueará.
La razón de esto es que UDP no tiene un búfer de envío real, todo lo que hace es copiar el búfer de la aplicación más abajo en la pila de protocolos y agregar encabezados UDP y encabezados IP en el proceso, por lo que en realidad no hay bloqueo. .
En modo sin bloqueo, la llamada de operación de envío regresará inmediatamente.
Nadie se opondrá a una devolución inmediata. Tomemos como ejemplo el bloqueo del envío. Cuando el búfer solo tiene 192 bytes, pero es necesario enviar 2000 bytes, la llamada regresa inmediatamente con un valor de retorno de 192. Como puede verse, el envío sin bloqueo solo copia la mayor cantidad de datos posible en el búfer, por lo que es posible que el envío sin bloqueo devuelva un valor menor que la longitud de envío en su parámetro.
¿Qué pasa si el buffer se queda sin espacio? En este momento definitivamente regresará de inmediato, pero obtendrá el error WSAEWOULDBLOCK/E WOULDBLOCK, lo que significa que no puede copiar ningún dato al búfer, por lo que será mejor que se tome un descanso e intente enviar nuevamente.
La operación sendto no se bloqueará en el modo sin bloqueo (consistente con el bloqueo, sin explicación).
2.recv (aquí se refiere específicamente a TCP) y recvfrom (aquí se refiere específicamente a UDP) se utilizan para describir la recepción.
En el modo de bloqueo, las operaciones recv y recvfrom se bloquearán hasta que haya al menos un byte (TCP) o un datagrama UDP completo en el búfer.
Cuando no lleguen datos, todas las llamadas a ellos se suspenderán y no regresarán.
Las operaciones recv y recvfrom volverán inmediatamente en modo sin bloqueo.
Si hay bytes de datos (TCP) o datagramas UDP completos en el búfer, devolverán el tamaño de los datos recibidos. Si no hay datos, se devuelve el error WSAEWOULDBLOCK/E WOULDBLOCK.
Lo anterior trata sobre la diferencia entre el envío y la recepción con bloqueo y sin bloqueo y el procesamiento del búfer. Espero que pueda ayudar a las personas que lean este artículo. Al mismo tiempo, también quiero corregir algunos conceptos erróneos en Internet. Si hay algún error en las expresiones del artículo, corríjalo. Gracias.