2010-05-11 11 views
24

Estamos usando .Net y sockets. El servidor está utilizando el método Socket.Sender (bytes []) por lo que simplemente envía toda la carga útil. Por otro lado, somos clientes que consumen los datos. Socket.Receive (buffer []). En todos los ejemplos de Microsoft (y otros), parecen quedarse con un tamaño de búfer de 8192. Hemos utilizado este tamaño, pero de vez en cuando estamos enviando datos a los clientes que exceden este tamaño de búfer.¿Cuál es un buen tamaño de búfer para la programación de socket?

¿Hay alguna forma de determinar la cantidad de datos que nos envió el método del servidor? ¿Cuál es el mejor tamaño de buffer?

Respuesta

31

Incluso si envía más datos que eso, es posible que no estén disponibles en una llamada a Recibir.

No se puede determinar la cantidad de datos que ha enviado el servidor: es una secuencia de datos, y solo está leyendo fragmentos a la vez. Puede leer parte de lo que el servidor envió en una llamada de envío, o puede leer los datos de dos llamadas de envío en una llamada de recepción. 8K es un tamaño de búfer razonable, no tan grande que perderá mucha memoria, y no tan pequeño que tendrá que usar muchas llamadas de recepción desperdiciadas. 4K o 16K posiblemente también estarían bien ... Yo personalmente no comenzaría a superar los 16K para los almacenamientos intermedios de la red. Sospecho que rara vez los llenarías.

Usted podría experimentar al tratar de usar un tampón muy grande y registrar cuántos bytes se recibieron en cada llamada - que le daría una idea de cuánto es generalmente disponibles - pero que no se muestran realmente el efecto de usar un buffer más pequeño. ¿Qué preocupaciones tienes sobre el uso de un buffer 8K? Si se trata de rendimiento, ¿tiene alguna evidencia de que este aspecto de su código es un cuello de botella de rendimiento?

+0

Me gustaría aumentar el tamaño del búfer si es posible. Estábamos considerando simplemente hacer 32K, pero estaba preocupado por el escenario anterior donde el comando de recepción no obtendría todo, aunque lo envié en un solo envío. – uriDium

+0

Lo siento, me olvidé de mencionar que estamos haciendo esto en modo bloqueo. Sin embargo, no creo que marque la diferencia. – uriDium

+3

@uriDium: debe escribir su código para que no dependa de recibir todo desde un único envío en una recepción. Ese no es el modelo que usa TCP, es un modelo * stream *. Si desea segmentar esa secuencia en mensajes distintos, debe usar un delimitador o escribir un prefijo de longitud para cada mensaje, de modo que el cliente sepa cuánto leer. –

1

8192 sería ideal. Si tiene datos que exceden este tamaño, sería mejor que envíe los datos en paquetes de longitud constante.

El tamaño de los datos enviados por el servidor se puede verificar utilizando la función recv en WINSOCK que tiene un parámetro que proporciona la longitud del búfer.

+0

8192 no es "ideal", pero es un número generalmente útil. No es mejor enviar los datos en paquetes de longitud constante: es mejor transmitirlos todo lo más rápido posible. El tamaño de los datos que se envían no necesariamente tiene que ver con el valor devuelto por 'recv()' en el par. Es un protocolo de transmisión. – EJP

6

Depende de su protocolo. Si espera mensajes de más de 8192 bytes, entonces debe aumentar el tamaño de su búfer según corresponda. Pero tenga en cuenta que este tamaño de buffer es solo para una llamada al Receive. Si realmente quiere/necesita hacerlo, puede repetir el ciclo Receive varias veces y copiar los datos recibidos en una estructura de datos o memoria intermedia arbitrariamente grande.

También tenga en cuenta que es una buena práctica llamar al Receive repetidamente hasta que haya verificado que ha leído todos los datos para un mensaje dado; incluso si un solo mensaje es menor que el tamaño de su búfer, aún así podría no ser recuperado por una sola llamada Receive.

4

Desafortunadamente, la respuesta de Jon Skeet deja una gran parte de la imagen: el tamaño del búfer de envío y el bandwidth-delay product de la tubería por la que está escribiendo.

Si está tratando de enviar datos a través de una tubería grande con un solo socket, y desea que TCP llene esa tubería, necesita usar un tamaño de búfer de envío que sea equivalente al producto de ancho de banda de la tubería. De lo contrario, TCP no llenará la tubería porque no dejará suficientes 'bytes en vuelo' en todo momento.

Considere una conexión que tiene una velocidad de 1 gigabit y tiene una latencia en un sentido de 10 milisegundos, en promedio. El tiempo de ida y vuelta (es decir, la cantidad de tiempo que transcurre entre el envío de un paquete por el socket y el tiempo que recibe el ack para ese paquete y, por lo tanto, sabe enviar más datos) suele ser el doble de la latencia.

Entonces, si tiene una conexión de 1 gigabit y un RTT de 20 milisegundos, esa tubería tiene 1 gigabit/seg * 20 milisegundos == 2.5 megabytes de datos en vuelo en todo momento si se utiliza por completo.

Si su búfer de envío TCP está a menos de 2.5 megabytes, entonces ese socket nunca utilizará completamente el conducto: nunca obtendrá un gigabit/seg de rendimiento de su socket.

Si su aplicación usa muchos sockets, entonces el tamaño agregado de todos los buffers de envío TCP debe ser de 2.5 MB para utilizar completamente esta tubería hipotética de 1 gigabit/20 ms RTT. Por ejemplo, si usa búferes de 8192 bytes, necesita 306 zócalos TCP simultáneos para llenar esa tubería.

Cuestiones relacionadas