.Net TCPIP Async Server unable to hold connections open.

I am trying to make a TCP IP Stream based server using the new async methods in .Net 4.5.  What I am trying to achieve is that when the server is started, it will listen for clients connecting to it.  Once client connects, it should hold the connection open for bi-directional traffic.

No more that two or three clients will ever connected, but usually it will only be one.

With each client I need to listen for <STX><DATA><ETX> string messages.   When we receive a message we pass it off to another class to decode and process, and we listen for the next message.

At the same time, we need to be able to send similarly formatted messages to a selected client.

I have found some code on the web, but I am very new to async programming, and am getting lost.  I would be grateful for any help anyone can offer.

What I found was:

public async void Run()
        {
            var listener = new TcpListener(IPAddress.Any, _port);
            listener.Start();
            
            while (true)
            {
                try
                {
                    var tcpClient = await listener.AcceptTcpClientAsync();
                    var t = Process(tcpClient);
                    await t;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }
        private async Task Process(TcpClient tcpClient)
        {
            var clientEndPoint = tcpClient.Client.RemoteEndPoint.ToString();
            Console.WriteLine("Received connection request from " + clientEndPoint);
            try
            {
                var networkStream = tcpClient.GetStream();
                var reader = new StreamReader(networkStream);
                var writer = new StreamWriter(networkStream) {AutoFlush = true};

                while (true)
                {
                    var request = await reader.ReadLineAsync();

                    if (request == null) break;

                    Console.WriteLine("Received service request: " + request);

                    OnMessageReceived(request);
                }

                tcpClient.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (tcpClient.Connected)
                    tcpClient.Close();
            }
        }

Open in new window


The problems I have with this is three fold.  Firstly, the server does not seems to be telling the client we have the message.  According to the client developers, we do not need to send an Ack, the normal TCP message handling should be fine.  This is causing the client to timeout, and reset and send the message again.

Secondly, and this may be related to the first, when we receive a correctly formatted message, and handle it, the program goes around to the ReadLineAsync again, but immediately receives a null message.  Again the client developers say they are not sending any nulls.

Finally, how can I find a specific client to send a message to, and how can I send it.  In the sample code it seems I can only send after I receive something.

Any and all help would be greatly appreciated, I have been trying all sorts of options, but everything ends in failure.
LVL 6
townsmaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

it_saigeDeveloperCommented:
Try implementing this rudimentary client/server sample (this should give you an idea of what it going on here):
Server Project (Program.cs) -
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace EE_Q28713048_Server
{
	class Program
	{
		static void Main(string[] args)
		{
			var cts = new CancellationTokenSource();
			var listener = new TcpListener(IPAddress.Any, 28000);
			listener.Start();
			Console.WriteLine("Listener is awaiting for client connections");
			var task = AwaitClientConnectionAsync(listener, cts.Token);
			while(Console.ReadKey().Key != ConsoleKey.Q);
			cts.Cancel();
			while (task.Status == TaskStatus.Running);
			Console.WriteLine();
			Console.WriteLine("Finished cancelling all tasks.  Press any key to exit.");
			Console.ReadLine();
		}

		async static Task AwaitClientConnectionAsync(TcpListener listener, CancellationToken token)
		{
			while (!token.IsCancellationRequested)
			{
				Console.WriteLine("Task is waiting for client connection...");
				Console.WriteLine("Press 'Q' to quit...");
				TcpClient client = await listener.AcceptTcpClientAsync();
				Console.WriteLine("Client requesting connection...");
				var task = TrySendResponse(client, token);
				while (task.Status == TaskStatus.Running);
			}
		}

		async static Task TrySendResponse(TcpClient client, CancellationToken token)
		{
			var buffer = new byte[4096];
			var stream = client.GetStream();
			token.Register(() => stream.Close());
			while(!token.IsCancellationRequested)
			{
				try
				{
					var read = await stream.ReadAsync(buffer, 0, buffer.Length, token);
					if (read != 0)
						Console.WriteLine("Received: {0}", Encoding.UTF8.GetString(buffer, 0, read));
					else
						break;

					await stream.WriteAsync(buffer, 0, read, token);
					Console.WriteLine("Response sent to client");
					Console.WriteLine("Press 'Q' to quit...");
				}
				catch (Exception ex)
				{
					Console.WriteLine(ex.Message);
				}
			}
		}
	}
}

Open in new window

Which produces the following output while waiting for the client instance to start -Capture.JPGClient Project (Program.cs) -
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace EE_Q28713048_Client
{
	class Program
	{
		static void Main(string[] args)
		{
			var task = Task.Factory.StartNew(async () =>
			{
				using (var client = new TcpClient())
				{
					await client.ConnectAsync(IPAddress.Parse("127.0.0.1"), 28000);
					Console.WriteLine("Connected to the server");
					using (var stream = client.GetStream())
					using (var writer = new StreamWriter(stream))
					using (var reader = new StreamReader(stream))
					{
						writer.AutoFlush = true;
						for (int i = 0; i < 10; i++)
						{
							Console.WriteLine("Writing to the server");
							await writer.WriteLineAsync(DateTime.Now.ToLongTimeString());
							Console.WriteLine("Reading response from the server");
							var response = await reader.ReadLineAsync();
							if (!string.IsNullOrWhiteSpace(response))
								Console.WriteLine("Response from server: {0}", response);
						}
					}
				}
				Console.WriteLine("Client has closed connection to server");
			});
			while (task.Status == TaskStatus.Running) ;
			Console.WriteLine();
			Console.WriteLine("Client has finished executing.  Press any key to exit.");
			Console.ReadLine();
		}
	}
}

Open in new window

Which produces the following output -Capture.JPGAnd effects the server instance like such -Capture.JPGAs I stated this is a very rudimentary example.
-saige-

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
townsmaAuthor Commented:
Many thanks for the reply, based on new information received from the developer of the client, and the information provided in the sample above, I have managed to get the interface working.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.