1. It's not Nagle

2. Keren is right - Mostly. I did take care to have my client flush its output buffer 
after each write, so the server
should have picked the same number of reads. After sending off my original query, I 
went for a long walk, and hit on the
answer, which I just finished implementing. It's this:

The listener thread, upon registering a client in the user table, allows the mux read 
thread to start collecting data.
Despite the flush, and despite my pacing the client messages 1/2 a second apart, the 
header and the first few records
get picked up. I grab the header and open the output file. All subsequent stuff goes 
to the output log file - apart from
the first few entries. The oddball thing, is thereafter there is no apparent buffering 
of client data. 

The solution is quite simple: Have the Java client do a (blocking) read (of say, one 
byte) on the socket after sending
the header. Have the server sent a single "sync" byte to the client immediately after 
opening the log file. And all
works just fine.

Apropos of reading a good book on TCP "kishkes" - I have Steven's 3 "Protocol" 
volumes: You need a year's
sabbatical from work to read them ...

I suppose that the moral of the story, is to prepare a query to the list, take a walk, 
and then send it to the trash
basket. Just the exercise of formulating a problem like this for someone else to read 
often carries its solution ...

Thanks for the replies.



Daniel Feiglin wrote:
> 
> This programming problebm is not specific to Linux; it can be reproduced under Unix 
>(e.g Solaris).
> 
> Here is the scenario: I have a C++ server (a sort of logger, a bit like syslog) and 
>many Java clients.
> 
> Each Java client sends the server a text header record which I'll describe in a 
>moment, and thereafter, user generated
> text "log" records. Every client write() (using the output stream obtained from the 
>socket), is followed by a flush()
> call, to ensure that each write() is indeed carried out.
> 
> The header record, a comma delimited list,  contains a file name, where I want the 
>server to throw out the subseqent
> stuff on a per client basis. It contains other fields not pertinent to this query.
> 
> The server is built in "classic" fashion: A listener thread, assigns each client a 
>file descriptor, and a multiplexed
> read thread (using select())
> processes reads from the clients. I use standard pthreads (Write once, run many).
> 
> When a Java client comes "on board", it first sends the header, upon which basis a 
>log file is opened by the server on
> the client's behalf. All subsequent message from that client are recognized as log 
>messages and written to the client's
> log file.
> 
> When a client disconnects, the server detects it (as a zero length read buffer) and 
>cleanly closes the file and the
> socket connection.
> 
> I maintain a table of online client records, which uses standard pthread mutexes to 
>avoid a few simple potential
> clashes.
> 
> Now for the problem:
> 
> When a client comes up, for some reason or other, the header and the first first few 
>log records are aggregated by TCP,
> and appear on select() as a single read(). All subsequent client writes are picked 
>up correctly.  I can vary the number
> of initially aggregated records by reducing the select() timeout (but not setting it 
>to zero!). The worst results are
> obtained, when I allow select() to block.
> 
> If for example, I set the select() timeout to say, 1 sec and force the client to 
>sleep 2 secs after issueing the header,
> I can make the problem "disappear", if for an obvious reason.
> 
> 1. Why does TCP aggregate the first few records, and then "settle down" and behave 
>as expected?
> 
> 2. Any suggested "fix"?
> 
> If it is felt that this is somewhat off-topic, please reply directly to me.
> 
> References: Stevens, UNP Vol 1, and APUE, syslog sources (for an example).
begin:vcard 
n:Feiglin;Daniel
x-mozilla-html:FALSE
adr:;;;;;;
version:2.1
email;internet:[EMAIL PROTECTED]
x-mozilla-cpt:;0
fn:Daniel Feiglin
end:vcard

Reply via email to