Sign in to follow this  
Calin

C# networking, threading

Recommended Posts

Found a chat client and server tutorial wich i'm trying to use as networking code for my game. The client code crashes/breaks on exit with "Unable to read data from the transport connection: A blocking operation was interrupted by a call to WSACancelBlockingCall" error
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace ChatClient
{
    public partial class Form1 : Form
    {
        // Will hold the user name
       
        private StreamWriter swSender;
        private StreamReader srReceiver;
        private TcpClient tcpServer;
        // Needed to update the form with messages from another thread
        private delegate void UpdateLogCallback(string strMessage);
        // Needed to set the form to a "disconnected" state from another thread
        private delegate void CloseConnectionCallback(string strReason);
        private Thread thrMessaging;
        private IPAddress ipAddr;
        private bool Connected;

        public Form1()
        {
            // On application exit, don't forget to disconnect first
            Application.ApplicationExit += new EventHandler(OnApplicationExit);
            InitializeComponent();
        }

        // The event handler for application exit
        public void OnApplicationExit(object sender, EventArgs e)
        {
            if (Connected == true)
            {
                // Closes the connections, streams, etc.
                Connected = false;
                swSender.Close();
                srReceiver.Close();
                tcpServer.Close();
            }
        }

       

        private void InitializeConnection()
        {
            // Parse the IP address from the TextBox into an IPAddress object
            ipAddr = IPAddress.Parse(txtIp.Text);
            // Start a new TCP connections to the chat server
            tcpServer = new TcpClient();
            tcpServer.Connect(ipAddr, 1986);

            // Helps us track whether we're connected or not
            Connected = true;


            // Send the desired username to the server
            swSender = new StreamWriter(tcpServer.GetStream());
            swSender.WriteLine(txtUser.Text);
            swSender.Flush();

            // Start the thread for receiving messages and further communication
            thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
            thrMessaging.Start();
        }

        private void ReceiveMessages()
        {
            // Receive the response from the server
            srReceiver = new StreamReader(tcpServer.GetStream());
            // If the first character of the response is 1, connection was successful
            string ConResponse = srReceiver.ReadLine();
            // If the first character is a 1, connection was successful
            if (ConResponse[0] == '1')
            {
                // Update the form to tell it we are now connected
                this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { "Connected Successfully!" });
            }
            else // If the first character is not a 1 (probably a 0), the connection was unsuccessful
            {
                string Reason = "Not Connected: ";
                // Extract the reason out of the response message. The reason starts at the 3rd character
                Reason += ConResponse.Substring(2, ConResponse.Length - 2);
                // Update the form with the reason why we couldn't connect
                this.Invoke(new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });
                // Exit the method
                return;
            }
            // While we are successfully connected, read incoming lines from the server
            while (Connected)
            {
                
                this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
            }
        }

        // This method is called from a different thread in order to update the log TextBox
        private void UpdateLog(string strMessage)
        {
            // Append text also scrolls the TextBox to the bottom each time
            txtLog.AppendText(strMessage + "\r\n");
        }

        // Closes a current connection
        private void CloseConnection(string Reason)
        {
            

            // Close the objects
            Connected = false;
            swSender.Close();
            srReceiver.Close();
            tcpServer.Close();
        }

        

        
    }
}





THe error pops inside the ReceiveMessages function in the while loop after the exit function is called I'm not sure if the reason relies in threading or something else. When the app breaks the connected var evaluates false so I don't even understand how the program gets in the while loop [Edited by - Calin on October 24, 2008 4:11:40 PM]

Share this post


Link to post
Share on other sites
Are you following this tutorial? Why I found the code you post is not complete?
I think this line is critical as well:

private void btnConnect_Click(object sender, EventArgs e)
{
// If we are not currently connected but awaiting to connect
if (Connected == false)
{
// Initialize the connection
InitializeConnection();
}
else // We are connected, thus disconnect
{
CloseConnection("Disconnected at user's request.");
}
}


Quote:

When the app breaks the connected var evaluates false so I don't even understand how the program gets in the while loop?

I think when you click the button, a separate thread is started, and this thread will delegate to another method: UpdateLogCallback() to receive msg, i think.

private void InitializeConnection()
{
// Parse the IP address from the TextBox into an IPAddress object
ipAddr = IPAddress.Parse(txtIp.Text);
// Start a new TCP connections to the chat server
tcpServer = new TcpClient();
tcpServer.Connect(ipAddr, 1986);

// Helps us track whether we're connected or not
Connected = true;
// Prepare the form
UserName = txtUser.Text;

// Disable and enable the appropriate fields
txtIp.Enabled = false;
txtUser.Enabled = false;
txtMessage.Enabled = true;
btnSend.Enabled = true;
btnConnect.Text = "Disconnect";

// Send the desired username to the server
swSender = new StreamWriter(tcpServer.GetStream());
swSender.WriteLine(txtUser.Text);
swSender.Flush();

// Start the thread for receiving messages and further communication
thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
thrMessaging.Start();
}

Share this post


Link to post
Share on other sites
>>Are you following this tutorial? Why I found the code you post is not complete?

Yes, I trimmed the unimportant bits.

>>I think this line is critical as well:

When you press the button while you are connected CloseConnection() is called, however that does the same thing as the other function I'm using - OnApplicationExit -

>>I think when you click the button, a separate thread is started, and this thread will delegate to another method: UpdateLogCallback() to receive msg, i think.

I don't know much about threading but to my mind the new thread should check the while condition each time it gives the while loop a spin.

[Edited by - Calin on October 25, 2008 6:20:02 AM]

Share this post


Link to post
Share on other sites
I don't know much about socket prog, but based on my google-fu (i found this new hot word in gamedev) , I found this and this. Hope it helps you.

Quoted from a guy in that post:
Quote:

Well, networking is kind of fragile. It relies on a lot of intermediate components outside your control and your own code needs to anticipate the kinds of things that can occur.

:)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this