Internal TCP/IP send buffer?

G

Guest

Guest
Archived from groups: microsoft.public.windowsnt.protocol.tcpip (More info?)

Hello,

I'm trying to make two applications talk to each other over TCP/IP. The
sender has small blocks of data that need to be transmitted to the receiver
as soon as possible. Untransmitted packets might become obsolete quickly
therefore I need to minimize buffering on both the sender and the receiver
side.

In theory you can do this by disabling Nagle and setting SO_RCVBUF and so
SO_SNDBUF to a small size (let's suppose one kilobyte for now). Tests show
however that there's an internal operating system buffer that is 63836
(65536-1700) bytes in size. What is this buffer, and what can I do to work
around it?

Here's some quick and (very) dirty sample code.

Both the sender and the receiver start with initializing a socket:

WSADATA wsad;
WSAStartup(MAKEWORD(2,0), &wsad);
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in sa;
int len = sizeof(sa);
ZeroMemory(&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(3333);
sa.sin_addr.s_addr = inet_addr ("127.0.0.1");
int nTotal = 0;

The receiver then accepts a connection and displays the bytes available for
read:

bind(s, (SOCKADDR*)&sa, len);
listen(s, SOMAXCONN);
SOCKET sock = accept(s, (SOCKADDR*)&sa, &len);
SetSocketOptions (sock);
while(TRUE) {
ioctlsocket(sock, FIONREAD, (u_long*)&nTotal);
printf("Receivable: %d bytes\n", nTotal);
Sleep(1000);
}
closesocket(sock);

The sender connects to the receiver and pushes down data one byte at a time:

connect(s, (SOCKADDR*)&sa, len);
SetSocketOptions (s);
while(TRUE) {
char sz[1];
send(s, sz, sizeof(sz), 0);
nTotal += sizeof(sz);
printf("Sent %d bytes (total:%d)\n", sizeof(sz), nTotal);
}

SetSocketOptions simply disables Nagle and sets both the receive and the
send buffers to one K:

void SetSocketOptions(SOCKET s)
{
DWORD dwPacketSize = 1024;
BOOL bTrue = TRUE;
setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&dwPacketSize,
sizeof(dwPacketSize));
setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&dwPacketSize,
sizeof(dwPacketSize));
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (PSTR)&bTrue, sizeof(bTrue));
}

Running the receiver produces the following (expected) output after the
sender connects:

Receivable: 1024 bytes
Receivable: 1024 bytes
..... etc

Running the sender produces the following:

.....
Sent 1 bytes (total:65881)
Sent 1 bytes (total:65882)
Sent 1 bytes (total:65883)
Sent 1 bytes (total:65884)

....Then it stops here due to blocking on a send() that has no matching
recv()

The sender has 1k of buffers to work with that we set in SO_SNDBUF. The
receiver has another 1k of buffers due to SO_RCVBUF. We've managed to cram
65884 bytes down send()'s throat without blocking. We know where 2kbytes are
buffered, so where do the other 63836 bytes live? Note that 64836 is a
suspicious number - one would expect an even 64kbytes (IPv4 datagram?). The
difference is exactly 1700 bytes, which is close to an ethernet payload size
(1500 bytes) plus some change (headers, etc).

Can this internal buffer be disabled or limited in size somehow?

Thanks,

Marton Anka
 
G

Guest

Guest
Archived from groups: microsoft.public.windowsnt.protocol.tcpip (More info?)

Look at networking NG link on Tom Fout article I wrote , the paragraph
"Zero length send buffers and blocking sends" .
You really can set size to zero ( use your app buffer ) or TCP stack buffer
because it's change the size of socket buffer automatically on modern
windows Oses due
to LAN speed
Arkady
P.S. Use cross-link ( few groups in address ) and not multi-link to save
your time

"Marton Anka" <marton@03am.com> wrote in message
news:#$sm1M9tEHA.3476@TK2MSFTNGP14.phx.gbl...
> Hello,
>
> I'm trying to make two applications talk to each other over TCP/IP. The
> sender has small blocks of data that need to be transmitted to the
receiver
> as soon as possible. Untransmitted packets might become obsolete quickly
> therefore I need to minimize buffering on both the sender and the receiver
> side.
>
> In theory you can do this by disabling Nagle and setting SO_RCVBUF and so
> SO_SNDBUF to a small size (let's suppose one kilobyte for now). Tests show
> however that there's an internal operating system buffer that is 63836
> (65536-1700) bytes in size. What is this buffer, and what can I do to work
> around it?
>
> Here's some quick and (very) dirty sample code.
>
> Both the sender and the receiver start with initializing a socket:
>
> WSADATA wsad;
> WSAStartup(MAKEWORD(2,0), &wsad);
> SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> sockaddr_in sa;
> int len = sizeof(sa);
> ZeroMemory(&sa, sizeof(sa));
> sa.sin_family = AF_INET;
> sa.sin_port = htons(3333);
> sa.sin_addr.s_addr = inet_addr ("127.0.0.1");
> int nTotal = 0;
>
> The receiver then accepts a connection and displays the bytes available
for
> read:
>
> bind(s, (SOCKADDR*)&sa, len);
> listen(s, SOMAXCONN);
> SOCKET sock = accept(s, (SOCKADDR*)&sa, &len);
> SetSocketOptions (sock);
> while(TRUE) {
> ioctlsocket(sock, FIONREAD, (u_long*)&nTotal);
> printf("Receivable: %d bytes\n", nTotal);
> Sleep(1000);
> }
> closesocket(sock);
>
> The sender connects to the receiver and pushes down data one byte at a
time:
>
> connect(s, (SOCKADDR*)&sa, len);
> SetSocketOptions (s);
> while(TRUE) {
> char sz[1];
> send(s, sz, sizeof(sz), 0);
> nTotal += sizeof(sz);
> printf("Sent %d bytes (total:%d)\n", sizeof(sz), nTotal);
> }
>
> SetSocketOptions simply disables Nagle and sets both the receive and the
> send buffers to one K:
>
> void SetSocketOptions(SOCKET s)
> {
> DWORD dwPacketSize = 1024;
> BOOL bTrue = TRUE;
> setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&dwPacketSize,
> sizeof(dwPacketSize));
> setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&dwPacketSize,
> sizeof(dwPacketSize));
> setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (PSTR)&bTrue, sizeof(bTrue));
> }
>
> Running the receiver produces the following (expected) output after the
> sender connects:
>
> Receivable: 1024 bytes
> Receivable: 1024 bytes
> .... etc
>
> Running the sender produces the following:
>
> ....
> Sent 1 bytes (total:65881)
> Sent 1 bytes (total:65882)
> Sent 1 bytes (total:65883)
> Sent 1 bytes (total:65884)
>
> ...Then it stops here due to blocking on a send() that has no matching
> recv()
>
> The sender has 1k of buffers to work with that we set in SO_SNDBUF. The
> receiver has another 1k of buffers due to SO_RCVBUF. We've managed to cram
> 65884 bytes down send()'s throat without blocking. We know where 2kbytes
are
> buffered, so where do the other 63836 bytes live? Note that 64836 is a
> suspicious number - one would expect an even 64kbytes (IPv4 datagram?).
The
> difference is exactly 1700 bytes, which is close to an ethernet payload
size
> (1500 bytes) plus some change (headers, etc).
>
> Can this internal buffer be disabled or limited in size somehow?
>
> Thanks,
>
> Marton Anka
>
>
>
 
G

Guest

Guest
Archived from groups: microsoft.public.windowsnt.protocol.tcpip (More info?)

What about UDP instead ?
Would it be more suitable for your task ?

"Marton Anka" <marton@03am.com> wrote in message
news:%23$sm1M9tEHA.3476@TK2MSFTNGP14.phx.gbl...
> Hello,
>
> I'm trying to make two applications talk to each other over TCP/IP. The
> sender has small blocks of data that need to be transmitted to the
receiver
> as soon as possible. Untransmitted packets might become obsolete quickly
> therefore I need to minimize buffering on both the sender and the receiver
> side.
>
> In theory you can do this by disabling Nagle and setting SO_RCVBUF and so
> SO_SNDBUF to a small size (let's suppose one kilobyte for now). Tests show
> however that there's an internal operating system buffer that is 63836
> (65536-1700) bytes in size. What is this buffer, and what can I do to work
> around it?
>
> Here's some quick and (very) dirty sample code.
>
> Both the sender and the receiver start with initializing a socket:
>
> WSADATA wsad;
> WSAStartup(MAKEWORD(2,0), &wsad);
> SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
> sockaddr_in sa;
> int len = sizeof(sa);
> ZeroMemory(&sa, sizeof(sa));
> sa.sin_family = AF_INET;
> sa.sin_port = htons(3333);
> sa.sin_addr.s_addr = inet_addr ("127.0.0.1");
> int nTotal = 0;
>
> The receiver then accepts a connection and displays the bytes available
for
> read:
>
> bind(s, (SOCKADDR*)&sa, len);
> listen(s, SOMAXCONN);
> SOCKET sock = accept(s, (SOCKADDR*)&sa, &len);
> SetSocketOptions (sock);
> while(TRUE) {
> ioctlsocket(sock, FIONREAD, (u_long*)&nTotal);
> printf("Receivable: %d bytes\n", nTotal);
> Sleep(1000);
> }
> closesocket(sock);
>
> The sender connects to the receiver and pushes down data one byte at a
time:
>
> connect(s, (SOCKADDR*)&sa, len);
> SetSocketOptions (s);
> while(TRUE) {
> char sz[1];
> send(s, sz, sizeof(sz), 0);
> nTotal += sizeof(sz);
> printf("Sent %d bytes (total:%d)\n", sizeof(sz), nTotal);
> }
>
> SetSocketOptions simply disables Nagle and sets both the receive and the
> send buffers to one K:
>
> void SetSocketOptions(SOCKET s)
> {
> DWORD dwPacketSize = 1024;
> BOOL bTrue = TRUE;
> setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char*)&dwPacketSize,
> sizeof(dwPacketSize));
> setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&dwPacketSize,
> sizeof(dwPacketSize));
> setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (PSTR)&bTrue, sizeof(bTrue));
> }
>
> Running the receiver produces the following (expected) output after the
> sender connects:
>
> Receivable: 1024 bytes
> Receivable: 1024 bytes
> .... etc
>
> Running the sender produces the following:
>
> ....
> Sent 1 bytes (total:65881)
> Sent 1 bytes (total:65882)
> Sent 1 bytes (total:65883)
> Sent 1 bytes (total:65884)
>
> ...Then it stops here due to blocking on a send() that has no matching
> recv()
>
> The sender has 1k of buffers to work with that we set in SO_SNDBUF. The
> receiver has another 1k of buffers due to SO_RCVBUF. We've managed to cram
> 65884 bytes down send()'s throat without blocking. We know where 2kbytes
are
> buffered, so where do the other 63836 bytes live? Note that 64836 is a
> suspicious number - one would expect an even 64kbytes (IPv4 datagram?).
The
> difference is exactly 1700 bytes, which is close to an ethernet payload
size
> (1500 bytes) plus some change (headers, etc).
>
> Can this internal buffer be disabled or limited in size somehow?
>
> Thanks,
>
> Marton Anka
>
>
>