|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
simple Socket Programming question.I am a bit new in socket programming and I have a question about what's the best way to implemnt a TCPClient that can receive long messages? The example I found in MSDN works for me but it downloads only the first chunck of data sent by the server I connect to. How can i make the code wait until the end of the message is received from the server? Changing the buffer size won't change anything as i guess the stream.Read() method returns after the first bunch of data is received from the server. I don't really know how many packets is that neither why it returns before everything is read but i guess that i need to add in some infrastructure that will do some waiting and / or looping and which will detect when all the data is read and that i can exit. I have done some research on the internet and the example i saw often did not care for this kind of longer message or were too complex or not working if not communicating with their own server implementation. I have no access on the server I connect to then I cannot change anything on that side. Here is the code i use from MSDN doc (TCPClient class): static void Connect(String server, String message) { try { // Create a TcpClient. // Note, for this client to work you need to have a TcpServer // connected to the same address as specified by the server, port // combination. Int32 port = 13000; TcpClient client = new TcpClient(server, port); // Translate the passed message into ASCII and store it as a Byte array. Byte[] data = System.Text.Encoding.ASCII.GetBytes(message); // Get a client stream for reading and writing. // Stream stream = client.GetStream(); NetworkStream stream = client.GetStream(); // Send the message to the connected TcpServer. stream.Write(data, 0, data.Length); Console.WriteLine("Sent: {0}", message); // Receive the TcpServer.response. // Buffer to store the response bytes. data = new Byte[256]; // String to store the response ASCII representation. String responseData = String.Empty; // Read the first batch of the TcpServer response bytes. Int32 bytes = stream.Read(data, 0, data.Length); responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes); Console.WriteLine("Received: {0}", responseData); // Close everything. stream.Close(); client.Close(); } catch (ArgumentNullException e) { Console.WriteLine("ArgumentNullException: {0}", e); } catch (SocketException e) { Console.WriteLine("SocketException: {0}", e); } Console.WriteLine("\n Press Enter to continue..."); Console.Read(); } Anyone can help me or point me to an adequate resource?Thanks a lot,Francois Malgreve Francois Malgreve wrote:
> I am a bit new in socket programming and I have a question about what's the With blocking reads (i.e. you're not using Begin* and End*), you run in> best way to implemnt a TCPClient that can receive long messages? a loop reading from the stream / socket until either (1) something you've read tells you that the stream has ended, or (2) the read returns 0, zero bytes read. For an example of (1), HTTP 1.1 with keep-alive requires a header in the response stream to tell the client how much data to expect. It looks like "Content-Length: <some number>\r\n". So, to read this kind of data, you'd read in the headers and parse them until the blank line in the HTTP response, then read that exact number of bytes in by looping around calling Socket.Read() or NetworkStream.Read(). For an example of (2), see the code as I've modified it below: > // Receive the TcpServer.response. MemoryStream buffer = new MemoryStream();> > // Buffer to store the response bytes. > data = new Byte[256]; > > // String to store the response ASCII representation. > String responseData = String.Empty; > for (;;) { int read = stream.Read(data, 0, data.Length); if (read == 0) // read of 0 bytes indicates end of stream. break; buffer.Write(data, 0, read); } // Now, buffer has all the data. You can convert it into an array // with ToArray() if desired. > // Close everything. You should use 'using' to dispose of both the client and the stream. If> stream.Close(); > client.Close(); > } an exception occurs in your existing code before these lines, the stream / client will never be closed. For actual tactics that will work for long-running downloads of large amounts of data, you could look into (1) streaming the download to a file on disk, and (2) getting a handle on how asynchronous sockets work to avoid lots of threads if you've got lots of concurrent downloads. -- Barry Dear Barry,
Thanks a lot for the quick answer, I found myself finally doing nearly the same thing. int numberOfBytesRead = stream.Read(data, 0, data.Length); string returndata = System.Text.Encoding.ASCII.GetString(data, 0, numberOfBytesRead); while (numberOfBytesRead > 0) { numberOfBytesRead = stream.Read(data, 0, data.Length); returndata += System.Text.Encoding.UTF8.GetString(data, 0, numberOfBytesRead); } And you are right about the "using", I will implement it right away. I don't have more than 1 concurrent download at a type then i don't need a asynchronous system. Nevertheless, my file downloaded can be pretty large and I would be really glad if you could point me to some information concerning the streaming strategy. Right now i put everything in a String as you can see in my code snippet and then write the string in a text file. Thanks again, Francois Malgreve. You are ight Show quote "Barry Kelly" <barry.j.ke***@gmail.com> wrote in message news:cpd5f21umo8t2gk0d7kp9j397gvei5npe2@4ax.com... > Francois Malgreve wrote: > >> I am a bit new in socket programming and I have a question about what's >> the >> best way to implemnt a TCPClient that can receive long messages? > > With blocking reads (i.e. you're not using Begin* and End*), you run in > a loop reading from the stream / socket until either (1) something > you've read tells you that the stream has ended, or (2) the read returns > 0, zero bytes read. > > For an example of (1), HTTP 1.1 with keep-alive requires a header in the > response stream to tell the client how much data to expect. It looks > like "Content-Length: <some number>\r\n". So, to read this kind of data, > you'd read in the headers and parse them until the blank line in the > HTTP response, then read that exact number of bytes in by looping around > calling Socket.Read() or NetworkStream.Read(). > > For an example of (2), see the code as I've modified it below: > >> // Receive the TcpServer.response. >> >> // Buffer to store the response bytes. >> data = new Byte[256]; >> >> // String to store the response ASCII representation. >> String responseData = String.Empty; >> > > MemoryStream buffer = new MemoryStream(); > for (;;) > { > int read = stream.Read(data, 0, data.Length); > if (read == 0) // read of 0 bytes indicates end of stream. > break; > buffer.Write(data, 0, read); > } > > // Now, buffer has all the data. You can convert it into an array > // with ToArray() if desired. > >> // Close everything. >> stream.Close(); >> client.Close(); >> } > > You should use 'using' to dispose of both the client and the stream. If > an exception occurs in your existing code before these lines, the stream > / client will never be closed. > > For actual tactics that will work for long-running downloads of large > amounts of data, you could look into (1) streaming the download to a > file on disk, and (2) getting a handle on how asynchronous sockets work > to avoid lots of threads if you've got lots of concurrent downloads. > > -- Barry > > -- > http://barrkel.blogspot.com/ Francois Malgreve wrote:
> I don't have more than 1 concurrent download at a type then i don't need a As you saw in the sample I wrote, I used a MemoryStream; you could> asynchronous system. Nevertheless, my file downloaded can be pretty large > and I would be really glad if you could point me to some information > concerning the streaming strategy. Right now i put everything in a String as > you can see in my code snippet and then write the string in a text file. consider using a FileStream instead. BTW, if the data is text, then you don't need to pass it through Encoding.ASCII - leave it alone. Any bytes with a value > 127 get converted to character value 63 ('?') by Encoding.ASCII. -- Barry |
|||||||||||||||||||||||