• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 560
  • Last Modified:

Storing stream writers

Ola,

I want to collect streamwriters that write to tcp clients. The code will work like it is made for only 1 client. But when we uncomment the two for loops ( that sould enable the storing of 2 clients ) the client all of a sudden does not receive the response anymore.
Why is that?

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using System.IO;

namespace AtomHTTPresponse
{
      class AtomHTTPresponse
      {
            private ArrayList lObjArrayList = new ArrayList();
            static void Main(string[] args)
            {
                  AtomHTTPresponse lObjAtomHTTPresponse = new AtomHTTPresponse();
                  TcpListener lObjTcpListner = new TcpListener( 9999 );
                  lObjTcpListner.Start();
                  
                  int lCntOuter = 0;
                  //for ( int lCntOuter = 0; lCntOuter < 3; lCntOuter++ )
                  //{
                        Console.WriteLine( "Listening for client " + lCntOuter );
                        TcpClient lObjTcpClient = lObjTcpListner.AcceptTcpClient();
                        Console.WriteLine( "Got client " + lCntOuter );
                        NetworkStream lObjNetworkStream = lObjTcpClient.GetStream();
                        
                        StreamReader reader = new StreamReader( lObjNetworkStream );
                        StreamWriter writer = new StreamWriter( lObjNetworkStream );
                        while (reader.Peek() >= 0)
                        {
                              char[] c = new char[256];
                              reader.Read(c, 0, c.Length);
                              //Console.Write(c);
                              // I am reading the stream but not writing to make sure I am sending the response after the request is done
                        }
                        lObjAtomHTTPresponse.lObjArrayList.Add( writer );
                        
                        int lCntInner = 0;
                        //for ( int lCntInner = 0; lCntInner < lObjAtomHTTPresponse.lObjArrayList.Count; lCntInner++ )
                        //{
                              Console.WriteLine( "Writing to client " + lCntInner );
                              StreamWriter writer2 = ( StreamWriter ) lObjAtomHTTPresponse.lObjArrayList[ lCntInner ];
                              writer2.Write( lCntInner + " clients connected" );
                              writer2.Flush();
                        //}
                  //}
            }
      }
}
0
DaFou
Asked:
DaFou
  • 9
  • 7
1 Solution
 
dukkorgCommented:
What exactly are you trying to accomplish here? Are you trying to do a chat server? I could probably help you better if I knew where you where going with all of this.
0
 
dukkorgCommented:
Also if you want to have more than one client connect and have them be able to send data back and forth to each other you’re going to have a very hard time without using threads. I would highly suggest using them.
0
 
DaFouAuthor Commented:
I am trying to make a DHTML chat server:

I am buzy for some time on this:
http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_21057802.html

threads are ok but I first need proof of concept
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
DaFouAuthor Commented:
Here I explain what I want to do actually:
http://www.experts-exchange.com/Web/Web_Servers/IIS/Q_20924430.html
0
 
dukkorgCommented:
Writing your own web server is probably the wrong way to go for this. You would be better off using ASP.Net.
0
 
DaFouAuthor Commented:
No, it will be extremly hard to impossible to do it in ASP.NET.
And further more I dont wat to write my own webserver. I simply need this concept to work and I am in the clear.
My DHTML chatserver will act much different then a webserver.

Please work with me on this if you have time. Ill take things step by step question by question to reflect the effort to several times 500 points. FOr now I'd like to know why i cant loop the code but I can do it once.

Regards
0
 
dukkorgCommented:
Here's a demo I did years ago that showed how to update a web page without refreshing the page (only in ie) that uses ASP.Net and XML Data Islands.:

http://www.dukk.org/demos/XmlDataIslandsPageUpdate/default.htm

This demo is only updating the time but there is nothing stopping it from being able to update a table full of chat message.

That would probably work better for what your trying to do. This way you have a someone on your web page that just posts using a form in another frame and it would tell the server to update this XML file. Then each client would get a new XML file with everyone's chat message's in it.
0
 
dukkorgCommented:
for web browsers that don't support XML Data Islands you could have the server generate flat HTMLfile with all the message's that tell the browser not to cache them and just have javascript refresh the page.
0
 
DaFouAuthor Commented:
Thank you Dukkorg for your suggestions.
I am fairly experianced in some other methods then the one i propose to make a chat application but this method I propose has been in my mind for a long time now and I jsut want to see it work.
So although other methods might work aswell or even better I really want to continue with my plan.
If all else fails I have bought books on c# and books on C# network programming and I will start reading them when they arive next week.
But I really hope experts exchange can help me figure my problems out before that time.

Regards
0
 
dukkorgCommented:
This code works just fine:

using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
using System.IO;

namespace AtomHTTPresponse
{
      class AtomHTTPresponse
      {
            private ArrayList lObjArrayList = new ArrayList();
            static void Main(string[] args)
            {
                  AtomHTTPresponse lObjAtomHTTPresponse = new AtomHTTPresponse();
                  TcpListener lObjTcpListner = new TcpListener( 9999 );
                  lObjTcpListner.Start();
               
                  for ( int lCntOuter = 0; lCntOuter < 3; lCntOuter++ )
                  {
                        Console.WriteLine( "Listening for client " + lCntOuter );
                        TcpClient lObjTcpClient = lObjTcpListner.AcceptTcpClient();
                        Console.WriteLine( "Got client " + lCntOuter );
                        NetworkStream lObjNetworkStream = lObjTcpClient.GetStream();
                          
                        StreamReader reader = new StreamReader( lObjNetworkStream );
                        StreamWriter writer = new StreamWriter( lObjNetworkStream );
                        while (reader.Peek() >= 0)
                        {
                              char[] c = new char[256];
                              reader.Read(c, 0, c.Length);
                              //Console.Write(c);
                        }
                        lObjAtomHTTPresponse.lObjArrayList.Add( writer );
                          
                        for ( int lCntInner = 0; lCntInner < lObjAtomHTTPresponse.lObjArrayList.Count; lCntInner++ )
                        {
                              Console.WriteLine( "Writing to client " + lCntInner );
                              StreamWriter writer2 = ( StreamWriter ) lObjAtomHTTPresponse.lObjArrayList[ lCntInner ];
                              writer2.Write( lObjAtomHTTPresponse.lObjArrayList.Count + " clients connected" );
                              writer2.Flush();
                        }
                  }
            }
      }
}

You just have to open a new web browser of telnet window for each client. I ran the above code and this was my response:

Listing for client 0
Got client 0
Writing to client 0
Listing for client 1
Got client 1
Writing to client 0
Writing to client 1
Listing for client 2
Got client 2
Writing to client 0
Writing to client 1
Writing to client 2

And each browser had the proper responses. One reason you may have been having issues is if you didn't start a new browser for each request. It will blow up if you refresh the page before you get all 3 clients loaded because the browser will close the socket and cause the writes to fail.
0
 
DaFouAuthor Commented:
and do the web browsers display the text send to them like the code would have them do at your end?
At my end the the browser displays the text with the loops commented. But shows an error when I uncomment the for loops.

And yes I use 3 different IE 6.0 browsers

Regards.
0
 
DaFouAuthor Commented:
and could you show me how to test this useing telnet?
0
 
DaFouAuthor Commented:
I found out that sometimes it works in where I connect to the server using
http://localhost:9999 in my IE 6.0 webbrowser and then it displays
0 clients connected

Then with another browser i connect to the server again using http://localhost:9999
That browser freezes and its display does not change.

On the first client however it now displays
0 clients connected0 clients connected
And that is a very good sign!!!!!!! kind of proof I can store the stream/connection and keep it open and write to it at a later time.

now when I stop the server client 1 is unchanged which is good but client 2 displays an error:
The page cannot be displayed


OR what can happen when the first client connects to the server is that is does act like the second client in the first situation described above



Why does it vary like this the behaviour?

Regards
0
 
dukkorgCommented:
My browsers showed text in them only after all 3 browsers loaded up.  This is probably because IE is expecting HTTP headers and not text and HTTP is also a disconnected protocol so if you continue to hold connections open like this IE will probably just kill them and return a request time out. This is also the same thing that's causing your second client to display an error. Simply put the HTTP protocol wasn't designed to do this so clients for the HTTP protocol such as IE will probably give you un-expected and maybe even random results.

To tests this using telnet on windows 2000/xp/2003 you can just open a command window by going to: start -> run -> and type "cmd" then you can type "telnet localhost 9999" to create a telnet session. For this code to work you'll need to press any key before it will respond with anything.

As fare as storing the NetworkStream and the StreamWriter/StreamReaders you'll probably want to make another object that's only job in life is to keep the TcpClient, NetworkStream, the StreamReader, and the StreamWriter all in one place. And then you could store that object in a ArrayList or Hashtable so you can easily keep all your connection separated.

Something like this:

public class ConnectionObjects
{
      public TcpClient TcpClient;
      public NetworkStream Stream;
      public StreamReader Reader;
      public StreamWriter Writer;

      public ConnectionObjects(TcpClient tcpClient)
      {
            this.TcpClient = tcpClient;
            this.Stream = tcpClient.GetStream();
            this.Reader = new StreamReader(this.Stream);
            this.Writer = new StreamWriter(this.Stream);
      }
}

This way you would have a central point to clean up a connection. Just a suggestion though...
0
 
DaFouAuthor Commented:
quote:
 "Simply put the HTTP protocol wasn't designed to do this so clients for the HTTP protocol such as IE will probably give you un-expected and maybe even random results."

Just because the HTTP protocol ( and web browsers ) was not designed to do this is the reason I want to pull it off.
I have a proof of concept as far as keeping the connection open/alive and having IE handle the responses as they come every 5 seconds. It works like a charm and ofcourse IIS sends a HTTP header before it sends anything else. That will be my next step to add an HTTP header. Ill let you know how I progress in this question


Here is the code I used in clasic ASP:

<%@ Language=VBScript %>
<%
Server.ScriptTimeout = 15 ' Letting the script run for 15 seconds is good for packet capture. I also tested 3600 and even longer using another way.
Response.Buffer = False

Dim cpBolCanRespond
cpBolCanRespond = True
While ( True )
     If ( Round( Timer() ) Mod 5 ) = 0 Then
          If cpBolCanRespond Then
               Response.Write "<script language=""javascript"">window.status = " & Round( Timer() ) & "</script>"
               cpBolCanRespond = False
          End If
     Else
          cpBolCanRespond = True
     End If
Wend
%>

Regards,
0
 
DaFouAuthor Commented:
Ahh yeah,

I did it :-) Now I need to introduce threads
http://www.experts-exchange.com/Programming/Programming_Languages/C_Sharp/Q_21091010.html

500 points again.
0

Featured Post

Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

  • 9
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now