send data through networkstream

bonedoc

Well-known member
Joined
May 4, 2006
Messages
112
Programming Experience
Beginner
I have a text byte array and an image byte array. I need to add them together into a stream to be read later, and I just cant figure out how to combine them. Right now, I add the header text to a buffer, and then the image to another buffer. I then write those to a memory stream. After this, I write the total memory stream to a buffer. When I look at the data in the buffer it is correct. However, it goes bad when I try to read/write the total buffer to my network stream (NWstream). It just turns to all zeros. Basically, I need to create 2 buffers to one and then shoot it to a stream. It goes bad when I read from the final buffer to throw it in the stream. Any advice?

VB.NET:
                            'add header to stream
                            Dim ms As New MemoryStream
                            Dim HeaderToSend(12) As Byte
                            HeaderToSend = System.Text.Encoding.ASCII.GetBytes("1N" & STX & Xstring)
                            ms.Write(HeaderToSend, 0, 12)
                            'add image in to ms

                            Dim fs As New FileStream(ImagePath, FileMode.Open, FileAccess.Read)
                            Dim br As New BinaryReader(fs)
                            Dim ImageBytes(fs.Length) As Byte
                            numBytesRead = br.Read(ImageBytes, 0, ImageBytes.Length)
                            ms.Write(ImageBytes, 0, ImageBytes.Length)

                            Dim TotalReader As New StreamReader(ms)
                            Dim TotalBytes(ms.Length) As Byte
                            '****Does bad after this
                            Dim TR = ms.Read(TotalBytes, 0, TotalBytes.Length)
                            NWStream.Write(TotalBytes, 0, ImageBytes.Length)

                            fs.Close()
                            br.Close()
                            ms.Close()
 
That was a lot of mess in one code block! Where should I start to tell what is wrong?? Is this supposed to be a joke? Are you trying to say you are totally lost? (*retorical*)
  • You declare 13 elements long byte array, then immediately assign it some unknown length byte array.
  • you write a maximum of 12 bytes of (A) into a memorystream - but perhaps less and perhaps not all source bytes.
  • you open a filestream, pointlessly wraps a binaryreader around it just to call Read to read the source into a new byte array buffer. then write buffer to memorystream.
  • you initialize a streamreader (TotalReader) with the memorystream content, but this is left here and not used further.
  • A new byte array (TotalBytes) is declared with size one element larger than the length of the memorystream. The length of the memorystream is also not necessarily equal to the length of its content because the memorystream allocates more empty space as it is filled (always doubles when reaching current limit)
  • declare a untyped TR object and assign it the number of bytes actually read from trying to read from current memorystream position (which is pointless since memorystream is currently at end). TR variable is left here and not used again.
  • the empty byte array (E) is written to networkstream.
That sums up just about every move made in code is wrong.

Why not write directly to networkstream? (wrapping binaryreader-writer also goes nicely sometimes) If you for some odd reason need to first write a constant length 'header' (which there is no reason to) then find the actual header length and fill with 0-bytes up to 12-13 or what you will. Then write directly the bytes read from filestream.

I would write the string as bytes, write the file length as bytes, then write the file itself directly to stream. At the other end you could use the binaryreader and ReadString, ReadInt64, ReadBytes all three directly from the networkstream. Actually I would not buffer the full file with ReadBytes, but read-write chunks to filestream at receiver.

I have a attached a very simple client-server set that does this, open the 'filesocketex.sln' solution file, it contains both client and server projects that both starts when you run/debug. With Client you can click to browser for a file to send, Server listens in a loop and receives all files sent by client. Each click starts a new connection, but there is no port management included - so each file must finish until you can send a new using same port. Received files are 'dumped' to application path.
 

Attachments

  • vbnet20-filesocketex.zip
    24.9 KB · Views: 162
Ok, That code works great! I have one question for you. Lets say that I want the server to return the file it recieved back to the client. Do I just put the Sends() sub in the server code and call it at the end of its Recieve Sub? What do I have to add to the client side to recieve it, a recieve sub?
 
I gather server will do some processing first and not return the same file immediately. If in the mean time the connection is shut down the server must connect to client, this means also client must include a server listener loop. If you by design keeps the connection open, you can just write back on the open networkstream.

When on open connection there is no "server" and "client" per se, just two endpoints communicating. What one endpoint sends (write) the other must receive (read).
For example if you want communication to be: client sends, server confirms, client sends again
For Client this means: WRITE READ WRITE
For server this means: READ WRITE READ
 
So, In this case, it sound like they would both have the exact same code, but flopped? How long will the "server" listen for a signal? When this gets more complicated and I have 2 seperate machines, what IP address do I use for the code? If I have a router, do I insert the outside IP address in the code? What if I want to use dynDNS to direct me to the correct computer? Sorry for all the questions.
 
Last edited:
So, In this case, it sound like they would both have the exact same code, but flopped?
As for read/write operations on the stream that is true. You define the communication protocol yourself and for the two endpoints the communication is always mirrored, when one writes the other reads, else they wouldn't be communicating. They both also must expect the same type of data, as per the defined protocol. If you expand the previous example it may go like this specifically:
client: WRITE string READ integer WRITE determined byte array
server: READ string WRITE integer READ determined byte array
When this gets more complicated and I have 2 seperate machines, what IP address do I use for the code?
If in local lan, use the private lan IPs (or wins machine name should also go).
If I have a router, do I insert the outside IP address in the code?
The connecting party (client) must use the servers public IP. As for the server I think it must listen on its private IP at specific port, because the router doing port forwarding redirects certain port calls from outside to private IPs. I can't verify this at the moment, TcpListener documentation says local address which could mean both public or private local address, I think it means private local address which is the real local address of network adapter. It may sound redundant for the server to always have to specify its own IP to listen, but a computer may have several network adapters and be connected to several networks at the same time to serve different purposes. You can also initialize the IPEndPoint with IPAddress.Any for the listener.
What if I want to use dynDNS to direct me to the correct computer?
Then client connects to this address instead of IP. The documentation example use the string address without the "http://" protocol prefix. What happens when you use string address is that the DNS server is given a request to resolve and does the lookup and returns the IP that is used internally.
 
I really appreciate your help John! I think I have one last question. I have them talking back and forth now. When the "client" is finished sending its request, it goes to get into the listening mode...but I get the "Only one usage of each socket is permited" error. Why would I get this when ClientSocket.Close was called before the listener was started?
 
Now you have both applications serving as both a server and a client? And you try to make both listen on the same port on the same machine? That you cannot, let each instance listen on its own dedicated port if you need to run several servers on same computer (or network adapter possibly). Note that I don't think this type of design where client=server is very common, much because with todays internet the client is usually behind one wall after the other.

The client connecting must have some indication about what server address/port to connect to, this is an important part of the client-server design. I mentioned port management briefly earlier, an example is this: you have a server accepting many clients and serving them at the same time, since each connection reserves a port you have design the communication to make this happen. There is a very easy solution in dedicating one specific port on server for establishing client connections (I usually refer to this as a "service port"), its only purpose is to accept any client connect and notify that client at what free port this sessions communication will take place. Both then disconnects from service port, server starts a new listener on the allocated new port (in addition to keeping the service port going ready for yet more clients), client now knowing where to get served connect to the given communication port and they make their will.
 
Hey John thanks for that! It is working SWEET.

Is there a way to tell if the server or client has lost its connection other than having the code crash?

How long will the server listen before it times out or crashes?

Should I close each thread after the "server" reads the stream, so they dont accumulate?
 
Last edited:
Try-Catch read/write operations.

TcpListener starts listening when you call Start method and stops when you call Stop methods. It will never timeout or crash. As with the project example posted you loop and check if the listener got a connection pending, if so (Begin)Accept it to try make a connection.

A connection is usually closed when the operation is finished.
 
Everything is going awesome. There is only one problem that I can figure out. When I close the server and client window, the app is still running. It will go until I actually press the stop button. That code you gave me did not have that problem. It only has one listen.Start() that is called, and when the form closes, listen.Abort() is called. Well, with my code, I start up new listener once it sends a message back to the client by calling:

listen = New Threading.Thread(AddressOf listener)
listen.Start()

The program wont shut down after the second thread is started, even though abort is called on form closing. What is going on there? Is there a way to close all threads? If I ermove the above code and close both forms, it shuts right down.
 
Perhaps not very nice that in the example, I should've notified the thread to stop looping instead and wait for that to happen in main thread before allowing the app end. This also means you need the thread reference to check for exit, alternative run a delegate with a callback and make sure all threads have called back before app end.
Try to implement what I just said with a boolean value that you check in loop, exit loop at given "abort" condition true/false.
 
That worked great! Thanks again! It is cool because this allows you to send text/info and the file. Awesome!
 
Hey, the compact framework does not have .BeginAcceptTCPClient or .EndAcceptTCPClient. Is there something else can do in the CF? I see .AcceptTCPclient and stop. I wonder what would work? Seems like there should be something. The sockets class has BeginAccept and EndAccept. Here is a nice compact framework article, but I cant figure out what to do:

http://www.awprofessional.com/content/images/0321133528/samplechapter/makofskych12.pdf
 
Accepting a pending connection in sync/async is not a big deal, its a fast operation. If you have to, you can pass the listener reference to a regular new thread and do the accept there.
 
Back
Top