Let’s look at how the system handles a typical send
call when the send buffer size is non-zero. When an
application makes a send call, if there is sufficient
buffer space, the data is copied into the socket’s
send buffers, the call completes immediately with success,
and the completion is posted. On the other hand, if
the socket’s send buffer is full, then the
application’s send buffer is locked and the send call
fails with WSA_IO_PENDING. After the data in the send
buffer is processed (for example, handed down to TCP
for processing), then Winsock will process the locked
buffer directly. That is, the data is handed directly
to TCP from the application’s buffer and the socket’s
send buffer is completely bypassed.
The opposite is
true for receiving data. When an overlapped receive
call is performed, if data has already been received
on the connection, it will be buffered in the socket’s
receive buffer. This data will be copied directly
into the application’s buffer (as much as will fit),
the receive call returns success, and a completion is
posted. However, if the socket’s receive buffer is
empty, when the overlapped receive call is made, the
application’s buffer is locked and the call fails with
WSA_IO_PENDING. Once data arrives on the connection, it
will be copied directly into the application’s buffer,
bypassing the socket’s receive buffer altogether.
Setting the per-socket buffers to zero generally will
not increase performance because the extra memory copy
can be avoided as long as there are always enough
overlapped send and receive operations posted. Disabling
the socket’s send buffer has less of a performance
impact than disabling the receive buffer because the
application’s send buffer will always be locked until it
can be passed down to TCP for processing. However,
if the receive buffer is set to zero and there are
no outstanding overlapped receive calls, any incoming
data can be buffered only at the TCP level. The TCP
driver will buffer only up to the receive window
size, which is 17 KB—TCP will increase these buffers
as needed to this limit; normally the buffers are much
smaller. These TCP buffers (one per connection) are
allocated out of non-paged pool, which means if the
server has 1000 connections and no receives posted at
all, 17 MB of the non- paged pool will be consumed!
The non-paged pool is a limited resource, and unless
the server can guarantee there are always receives
posted for a connection, the per-socket receive buffer
should be left intact.
Only in a few specific
cases will leaving the receive buffer intact lead to
decreased performance. Consider the situation in which a
server handles many thousands of connections and cannot
have a receive posted on each connection (this can
become very expensive, as you’ll see in the next
section). In addition, the clients send data sporadically.
Incoming data will be buffered in the per-socket
receive buffer and when the server does issue an
overlapped receive, it is performing unnecessary work. The
overlapped operation issues an I/O request packet (IRP)
that completes, immediately after which notification is
sent to the completion port. In this case, the server
cannot keep enough receives posted, so it is better
off performing simple non-blocking receive calls.
WinSocket如何处理一个典型的数据请求
最新推荐文章于 2017-06-23 23:44:05 发布