Sign in to follow this  

[.net] C# .NET v1.1 Remoting - Existing Clients Experience Delays When a Client Quits

This topic is 4165 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi guys, I'm writing a simple chat application to get to grips with Remoting. I basically have a remoting object that is hosted within a Windows service as a server-activated singleton. The clients connect via a Windows application. It's working 90% as expected. Problems arise, however, when a client application is closed. For example, let's say I have 3 clients connected: A, B and C. Sending messages from/to these clients all works as expected. However, if any of the client applications are closed, the other client applications experience what seems to be a 5 second delay in receiving the next message (assuming I've sent it right after the initial client was closed), but I can't figure out why. Here's the remoting object:
using System;

namespace ChatRemote
{
	/// <summary>
	/// The remoting object.
	/// </summary>
	public class ChatRemoter : MarshalByRefObject
	{
		public ChatRemoter() {}

		public event MessageArrivedHandler MessageArrived;

		public void BroadcastMessage(MessageArrivedEventArgs e)
		{
			MessageArrivedHandler msgHandler = null;

			foreach (Delegate msgDelegate in MessageArrived.GetInvocationList())
			{
				try
				{
					msgHandler = (MessageArrivedHandler) msgDelegate;
					msgHandler(this, e);
				}
				catch 
				{
					MessageArrived -= msgHandler;
				}
			}
		}
	}

	[Serializable()]
	public class MessageArrivedEventArgs : EventArgs
	{
		private string user;
		private string message;

		public MessageArrivedEventArgs(string user, string message)
		{
			this.user = user;
			this.message = message;
		}

		public string User
		{
			get { return user; }
		}

		public string Message
		{
			get { return message; }
		}
	}

	public delegate void MessageArrivedHandler(object sender, MessageArrivedEventArgs e);
}



The remoting object is configured on the server via the OnStart method of the Windows service, as follows:
protected override void OnStart(string[] args)
{
	// Setup binary deserialization
	BinaryServerFormatterSinkProvider serverProv = new 
		BinaryServerFormatterSinkProvider();
	serverProv.TypeFilterLevel = 
	System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

	BinaryClientFormatterSinkProvider clientProv = new 
		BinaryClientFormatterSinkProvider();

	IDictionary props = new Hashtable();
	props["port"] = 80;

	// Setup the port on which the server will listen for connections.
	HttpChannel chan = new HttpChannel(props, clientProv, serverProv);        
	ChannelServices.RegisterChannel(chan);

	// Register the remoting object.
	RemotingConfiguration.RegisterWellKnownServiceType(
		typeof(ChatRemoter),
		"Chat",
		WellKnownObjectMode.Singleton);
}



The client is configured via the client form's constructor:
public MessageForm()
{
	//
	// Required for Windows Form Designer support
	//
	InitializeComponent();
	
	// Setup binary deserialization
	BinaryServerFormatterSinkProvider serverProv = new 
		BinaryServerFormatterSinkProvider();
	serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

	BinaryClientFormatterSinkProvider clientProv = new 
		BinaryClientFormatterSinkProvider();

	IDictionary props = new Hashtable();
	props["port"] = 0;

	// Register an HTTP channel to receive incoming messages.
	HttpChannel chan = new HttpChannel(props, clientProv, serverProv);        
	ChannelServices.RegisterChannel(chan);

	// Get a reference to the remoting object and store it.
	remoteObj = (ChatRemoter) Activator.GetObject(
		typeof(ChatRemoter),
		"http://localhost:80/Chat");

	// This is just here for debugging for now.  Will make it more robust later.
	try
	{
		remoteObj.MessageArrived += new MessageArrivedHandler(remoteObj_MessageArrived);
	}
	catch (System.Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}



Finally, the messages are sent/received in the following fashion:
public void remoteObj_MessageArrived(object sender, MessageArrivedEventArgs e)
{
	txtMessagesReceived.Text += e.User + ": " + e.Message + "\r\n";
}

private void btnSendMessage_Click(object sender, System.EventArgs e)
{
	remoteObj.BroadcastMessage(new MessageArrivedEventArgs(username, txtSendMessage.Text));
}



I'm not really sure why the other clients would experience delays after one client has quit. I've tried setting the remoting object to null and calling the Dispose() method of the form, but that didn't help. At first I thought it had something to do with the client calls being synchronous, but because the clients are exiting properly, I've no idea what the cause could be. I read somewhere that there are some issues with .NET v1.1 in terms of connection pooling, but I don't really see how this would apply in this case. I realise this is quite a lengthy post, but could anyone please shed some light on this?

Share this post


Link to post
Share on other sites
MY suspicion is that attempting to call the remote delegate (msgHandler(this, e) in your first file) blocks for a while as it tries to contact the client before it throws an exception.

If the delay is not acceptable, and that is the cause, you will have to run the delegate for each client asynchronously. That shouldn't be too hard hopefully!

Share this post


Link to post
Share on other sites
It's funny you should post that just now, because I've been trying things since I've posted and there really must be some kind of blocking going on. I tried testing with only 1 client connecting to the server, and after shutting that client down and restarting it, the same behaviour occurred. I wasn't sure before, because of the number of clients. I wondered if possibly they were blocking, but that doesn't seem to be the case.

I haven't used asynchronous calls with C# yet, so I'll try that now. I was reluctant to do that before because I didn't feel as though I understood the problem enough. It felt as though I might just be making the debugging process harder by adding asynchronous calls.

Probably time to try it now though. Thanks for the reply. Hopefully I can get something up and running.

Share this post


Link to post
Share on other sites
Oh and one thing I forgot to mention: it doesn't actually throw any exception. That was what I found confusing at first, until I tried with the 1 client. It really must be executing correctly, which surely means it has to be waiting for something or processing something else (which I'd be amazed if it was).

Share this post


Link to post
Share on other sites

This topic is 4165 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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