NetworkStream .Write() method not working every time

  • Thread starter Thread starter JeremyH
  • Start date Start date
J

JeremyH

This is a repost from my message in the ...language group. I need
help ASAP - working on a deadline.

I'm trying to create a simple, synchronous TCP client program to
receive requests and return data. My code very closely resembles the
example code provided in the Help files, but I find that the .Write
method - when run at full speed - only seems to successfully write
data the first time it is called.

For testing purposes, I am using Hyperterminal on another computer to
send 4 characters. The program always successfully reads all 4
characters. It is then supposed to reverse them and send the reversed
byte array back. Here is the code:

Private tcpLstn As New TcpListener(51112)

Public Sub subMainLoop()
Dim tcpClnt As TcpClient
Dim ns As NetworkStream
Dim buffr(4) As Byte
Dim buffr2(6) As Byte
Dim iRead As Integer

bScan = True

tcpLstn.Start()

While bScan
'--- Code execution pauses here until TCP connection
request
'--- is received.
tcpClnt = tcpLstn.AcceptTcpClient()

ns = tcpClnt.GetStream()

'--- Wait until 4 characters are successfully read
iRead = 0
While iRead < 4
iRead = iRead + ns.Read(buffr, iRead, 4 - iRead)
End While

'--- Create array of characters to send back
buffr2(0) = 13
buffr2(1) = 10
buffr2(2) = buffr(3)
buffr2(3) = buffr(2)
buffr2(4) = buffr(1)
buffr2(5) = buffr(0)

Try
'--- Send requested data over TCP port
ns.Write(buffr2, 0, 6)
ns.Close()
tcpClnt.Close()
Catch e As Exception
Console.WriteLine(e.ToString())
End Try

'--- Process events
Application.DoEvents()
End While

tcpLstn.Stop()

End Sub


When stepping through in debug mode, the ns.Write(buffr2, 0, 6)
command works about 95% of the time, and the returned characters are
displayed in HyperTerminal. When running the program with no breaks
and no MsgBox calls in the main loop, the program only successfully
writes back the 4 characters (plus {LF}{CR}) the first time. From
HyperTerminal (and other testing methods) I can tell that the 4
characters I send ARE, in fact, being read by the program EVERY time.
The response simply isn't coming through.

Ultimately, the program is only ever going to be communicating with
one other computer. So there isn't any need for multi-threading or
asynchronous reading/writing.

Am I missing something, though?
 
Also note that when I test using HyperTerminal on the same machine as the program (using the 127.0.0.1 loopback IP address), the program successfully sends the data to HyperTerminal MOST of the time, but still fails about 5%.

And when I say fails, I mean that nothing happens. No error, no data showing up in HyperTerminal, nothing. The program just keeps running and the "sent" bytes disappear into limbo

Problem with my network card maybe???
 
I can't believe that in this day in age there are still inherent timing issues/bugs in released development classes. This is RETARDED!!

The problem, it turns out, is that the NetworkStream .Write() method returns IMMEDIATELY. It does NOT wait until the data has actually been sent. Microsoft claims that it returns after making sure the data was added to the STREAM. This may be the case. However, there is no guarantee that the stream has actually been sent before closing the connection

My code reads like this
...
ns.Write(buffr2, 0, 6
ns.Close(
tcpClnt.Close(
...

Problem was: ns.Close() and tcpClnt.Close() were getting called before the data stream was actually sent - i.e. the underlying socket got closed before completing pending data transmissions. The code is/will be running on a P4 1.8GHz+ processor. The fix was to put in a manual loop delay (which any decent program should NEVER have to resort to) right after the ns.Write() command. This is a sucky solution, but the only one that works

...
ns.Write(buffr2, 0, 6
For i = 1 to 100000
i =
Nex
ns.Close(
tcpClnt.Close(
...

I tried enabling tcpClnt.LingerState, setting tcpClnt.NoDelay = True, raising the tcpClnt.LingerTime, making sure the .SendBuffer was set low since I am only sending 6 bytes at a time - but none of those things made any difference. THE ONLY WAY to avoid the timing limitation on sending data is to create a manual delay or have other code executing before calling the .Close() methods

Someone needs to put this in a book/article somewhere
 
Back
Top