• Welcome to Valhalla Legends Archive.
 

[C#] TcpClient Error?

Started by Yegg, January 01, 2006, 12:13 PM

Previous topic - Next topic

Yegg

I really cannot figure out what is wrong with a certain function in my application. Whenever I clicked the button on my application that activates this function, the program freezes and an hour glass appears, if I click on it I get the "(Not Responding)" appended to my title. I have reason to believe that the following code is what must be causing the issue.

            if (lstFiles.Items.Count < 1)
            {
                rtbInfo.AppendText("You have not specified any files to send.\n");
                return;
            }
            TcpClient sckTCP;
            try
            {
                sckTCP = new TcpClient("192.168.1.103", 17545);
                rtbInfo.AppendText("A connection has been made with the server!\n");
            } catch {
                rtbInfo.AppendText("Could not establish a connection!\n");
                return;
            }


However the first part of this, which is the if-statement checking lstFiles.Items.Count can't possible cause a problem, so it must be the second part. '192.168.1.103' is another computer on my network, on it is a small Python script I wrote to handle the connection from this C# program. The port of 17545 is just an arbitrary port I decided to choose. As you can see, the program should connect to that address and append some text to my program, however when this function runs, this does not happen. But I do know that the program is connecting to the other computer. Why? The Python script I wrote outputs text to the console notifying the user when another computer has connected to it. So I know that the code is for the most part working, but the reason it crashes before even finishing rtbInfo.AppendText() is beyong me. Any help would be greatly appreciated.

Edit: I forgot to mention it, but the port is forwarded properly.

MyndFyre

Can you verify this through debugging?  Set a breakpoint on the line "rtbInfo.AppendText("A connection has been made with the server!\n");" and launch the program in the debugger.  If you never reach the breakpoint then the constructor is hanging.

If you determine that this is the case, you can manually resolve to determine where exactly the problem is occurring:


// resolution
IPAddress destAddress = Dns.Resolve("192.168.1.103").AddressList[0];
IPEndPoint destEP = new IPEndPoint(destAddress, 17545);
sckTCP = new TcpClient(destEP);
// connection
sckTCP.Connect();


Put that all within the try block, and I suggest that in non-release builds, you catch (Exception ex) so that you can examine error information -- or that you re-throw the exception to a higher-level handler.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Yegg

Hmm, I'm pretty inexperienced with debugging, however I'm quite sure it reached the breakpoint, in fact, it even passed it.

For the following code

            TcpClient sckTCP;
            try
            {
                sckTCP = new TcpClient("192.168.1.103", 17545);
                rtbInfo.AppendText("A connection has been made with the server!\n");
            } catch {
                rtbInfo.AppendText("Could not establish a connection!\n");
                return;
            }
            NetworkStream nStream = sckTCP.GetStream();
            StreamReader sReader = new StreamReader(nStream);
            StreamWriter sWriter = new StreamWriter(nStream);


I have the following debug information

Name                     Value
sckTCP                             {System.Net.Sockets.TcpClient}
nStream                           null
sReader                           null
sWriter                             null

Note that I left our the types of these variables. 

I may have read the debugger incorrectly,. But with the information I've shown you, does this mean it has gone as far as sWriter?

This may sound odd, but I've never really don't debugging before. I've been using interpreted languages for some time, while they do have debugging, you don't usually find the need for it as you do with languages such as C#.

MyndFyre

In Visual Studio during debugging, once you hit the breakpoint, the debugger waits for your okay to continue.  From then, you can choose to continue normally ("Continue" - this looks like a play button), or one of three step-and-break-again functions, "Step In," "Step Over", and "Step Out."

"Step In" functions the same as "Step Over" unless you're at a function call that you have code for.  For example, if you write the function "DoStuff()", and call it, if you're at that function call and you choose Step In, your next breakpoint will be the first instruction within DoStuff().  Non-user code, like library calls (such as Socket.Connect()) do not have source code available, and therefore do not allow us to step into them.

"Step Over" is the next step -- if you wrote "DoStuff()" and were at a call to it, "DoStuff()" would be called and executed, and the debugger will break at the next instruction at the current scope.  This is roughly how "Step In" works with library functions.

"Step Out" is fairly straightforward: if you're withing "DoStuff()" and click Step Out, then you'll exit the current scope (you'll exit DoStuff()) and you'll go to the first instruction after the function was called.  Sometimes this means you'll exit to the main message loop, and since there's no debuggable user code there, you'll just return to the Form window.

What I wanted you to do was to set a breakpoint where I told you, start normally, and then when you get to the breakpoint, click Step Over to see whether it was the TcpClient constructor causing the issue, or the AppendText function.

There is a known issue with the .NET Platform 1.x and rich text boxes that I seem to have found a workaround for (afaik they haven't patched this in service packs).  I don't believe I ever updated that  thread to indicate the workaround, so here it is.  You might be experiencing the same issue (IIRC, there was a similar unresponsive app situation when I found it).

The issue arises when you're trying to modify the text in the RichTextBox when you're in a thread other than the one that created the RTB's handle.  This is an issue for most controls (you're only supposed to repaint in the original thread), but it seems to me that Microsoft could have wrapped this into the function calls asynchronously instead of making us do it for every function or property we want to use.  The workaround involves writing a wrapper function and calling the BeginInvoke method on the control:


// this can be class-level or a child of the class that's hosting your rich text box.
// it cannot be declared in a function.
internal delegate void AppendTextCallback(string text);

// add these methods and member to your class that's hosting the RTB.
private void AppendTextToRtb(string text) {
  rtbInfo.BeginInvoke(new AppendTextCallback(this.AppendTextToRtbImpl, text));
}
private void AppendTextToRtbImpl(string text) {
  rtbInfo.AppendText(text);
}


The method AppendTextToRtbImpl is what actually does the appending.  The wrapper function AppendTextToRtb is what you should call -- it begins the implementation call on the same thread as the rich text box used to be created.  So, instead of this call:

rtbInfo.AppendText("A connection has been made with the server!\n");

you have:

AppendTextToRtb("A connection has been made with the server!\n");


If you find that the application hangs after the call to the AppendText method and NOT the TcpClient constructor, you'll probably be more successful by replacing the call to the rich text box.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Yegg

Sorry I too so long to respond, MydnFyre. Thank you for explaining the procedures I can use with debugging, those helped out a great deal. However there is a problem with the code you provided.

private void AppendTextToRtb(string text) {
  rtbInfo.BeginInvoke(new AppendTextCallback(this.AppendTextToRtbImpl, text));
}


When I try to build or run my application, I receive an erroe saying that a method is expected. This is caused because AppendTextCallback is given 2 arguments while it was created to accept only one I guess. When I give it just the argument of this.AppendTextToRtbImpl or AppendTextToRtbImpl it works fine, but of course it now cannot append any text because it has been given no text to append. When I get some more free time, I'll be trying something involving threading to see if I can hopefuly solve the issue.