Click here to Skip to main content
15,881,852 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hi,

This is almost identical to the Microsoft example of an ASync Client/Server TCPIP application, the only changes I've made is to support IPV6 and to listen again for the next connection. This is where I've come into a problem, listening again. I've tried disposing of the socket but that doesn't seem to help. I continuously receive this error:

5/3/2014 7:45:32 PM, Only one usage of each socket address (protocol/network address/port) is normally permitted, at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Bind(EndPoint localEP)
at CInstaller.CInstall.WaitForConnection() CInstall.cs:line 163

I start a new thread at the end of ReadCallback to wait for another connection. I've indicated where line 163 is below with <<<< Problem Line

Any help is greatly appreciated...

Thanks,
Glenn


C#
private void WaitForConnection()
        {
            string work;

            Int32 port;
            byte[] bytes = new Byte[1024];

            try
            {
                if (string.IsNullOrEmpty(GetSet.TCPIPPort))
                {
                    Thread.Sleep(200);
                    if (string.IsNullOrEmpty(GetSet.TCPIPPort))
                    {
                        if (!EventLog.SourceExists(GetSet.ProductName))
                            EventLog.CreateEventSource(GetSet.ProductName, "Application");

                        eventLogInstaller.Source = GetSet.ProductName;
                        eventLogInstaller.Log = "Application";
                        work = string.Format("{0}, {1}:  ", DateTime.Now, "TCPIP Port not set, service terminating.");
                        eventLogInstaller.WriteEntry(work);
                        this.Stop();
                    }
                }

                port = Convert.ToInt32(GetSet.TCPIPPort);

                // Establish the local endpoint for the socket.
                // The DNS name of the computer
                // running the listener is 
                IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
                IPAddress ipAddress = ipHostInfo.AddressList[0];
                IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);

                // Create a TCP/IP socket.
                Socket listener = new Socket(ipAddress.AddressFamily,
                    SocketType.Stream, ProtocolType.Tcp);

                work = string.Format("{0} {1} - Waiting for connection on IPAddress: {2}, port {3}", 
                                    GetSet.ProductName, DateTime.Now, ipAddress, GetSet.TCPIPPort);
                Trace.WriteLine(work);

                // Bind the socket to the local endpoint and listen for incoming connections.
                listener.Bind(localEndPoint); // <<<<< Problem line
                listener.Listen(100);

                while (true)
                {
                    // Set the event to nonsignaled state.
                    allDone.Reset();

                    // Start an asynchronous socket to listen for connections.
                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);

                    // Wait until a connection is made before continuing.
                    allDone.WaitOne();
                    break;
                }
            }

            catch (Exception ex)
            {
                if (!EventLog.SourceExists(GetSet.ProductName))
                    EventLog.CreateEventSource(GetSet.ProductName, "Application");

                eventLogInstaller.Source = GetSet.ProductName;
                eventLogInstaller.Log = "Application";

                work = string.Format("{0}, {1}, {2}", DateTime.Now, ex.Message, ex.StackTrace);
                eventLogInstaller.WriteEntry(work);
                Trace.WriteLine(work);
                return;
            }
        }

        public void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                work = string.Format("{0} {1} - AcceptCallback Start",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);

                // Signal the main thread to continue.
                allDone.Set();

                // Get the socket that handles the client request.
                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);

                // Create the state object.
                StateObject state = new StateObject();
                state.workSocket = handler;
                handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReadCallback), state);

                work = string.Format("{0} {1} - AcceptCallback End",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);
            }

            catch (Exception ex)
            {
                if (!EventLog.SourceExists(GetSet.ProductName))
                    EventLog.CreateEventSource(GetSet.ProductName, "Application");

                eventLogInstaller.Source = GetSet.ProductName;
                eventLogInstaller.Log = "Application";

                work = string.Format("{0}, {1}, {2}", DateTime.Now, ex.Message, ex.StackTrace);
                eventLogInstaller.WriteEntry(work);
                Trace.WriteLine(work);
                return;
            }
        }

        public void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;
            Thread threadProcessMessage;

            try
            {
                work = string.Format("{0} {1} - ReadCallback Start",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);

                // Retrieve the state object and the handler socket
                // from the asynchronous state object.
                StateObject state = (StateObject)ar.AsyncState;
                Socket handler = state.workSocket;

                // Read data from the client socket. 
                int bytesRead = handler.EndReceive(ar);

                if (bytesRead > 0)
                {
                    // There  might be more data, so store the data received so far.
                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                    // Check for end-of-file tag. If it is not there, read 
                    // more data.
                    content = state.sb.ToString();
                    if (content.IndexOf("<EOF>") > -1)
                    {
                        GetSet.Message = content;
                        // All the data has been read from the client, write it to trace file
                        mreInstallThread.Reset();
                        threadProcessMessage = new Thread(new ThreadStart(ProcessMessage));
                        threadProcessMessage.Start();
                        
                        work = string.Format("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
                        Trace.WriteLine(work);

                        // Echo the data back to the client.
                        Send(handler, content);
                        mreInstallThread.WaitOne(375);
                    }
                    else
                    {
                        // Not all data received. Get more.
                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                                             new AsyncCallback(ReadCallback), state);
                    }
                }

                Thread.Sleep(1000);

                GetSet.threadInstallComm = new Thread(new ThreadStart(WaitForConnection));
                GetSet.threadInstallComm.Start();

                work = string.Format("{0} {1} - ReadCallback End",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);
            }

            catch (Exception ex)
            {
                if (!EventLog.SourceExists(GetSet.ProductName))
                    EventLog.CreateEventSource(GetSet.ProductName, "Application");

                eventLogInstaller.Source = GetSet.ProductName;
                eventLogInstaller.Log = "Application";

                work = string.Format("{0}, {1}, {2}", DateTime.Now, ex.Message, ex.StackTrace);
                eventLogInstaller.WriteEntry(work);
                Trace.WriteLine(work);
                return;
            }
        }

        private void Send(Socket handler, String data)
        {
            try
            {
                work = string.Format("{0} {1} - Send Start",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);

                // Convert the string data to byte data using ASCII encoding.
                byte[] byteData = Encoding.ASCII.GetBytes(data);

                // Begin sending the data to the remote device.
                handler.BeginSend(byteData, 0, byteData.Length, 0,
                    new AsyncCallback(SendCallback), handler);

                work = string.Format("{0} {1} - Send End",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);
            }

            catch (Exception ex)
            {
                if (!EventLog.SourceExists(GetSet.ProductName))
                    EventLog.CreateEventSource(GetSet.ProductName, "Application");

                eventLogInstaller.Source = GetSet.ProductName;
                eventLogInstaller.Log = "Application";

                work = string.Format("{0}, {1}, {2}", DateTime.Now, ex.Message, ex.StackTrace);
                eventLogInstaller.WriteEntry(work);
                Trace.WriteLine(work);
                return;
            }
        }

        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                work = string.Format("{0} {1} - SendCallback Start",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);
                // Retrieve the socket from the state object.
                Socket handler = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.
                int bytesSent = handler.EndSend(ar);
                work = string.Format("Sent {0} bytes to client.", bytesSent);
                Trace.WriteLine(work);

                handler.Shutdown(SocketShutdown.Both);
                handler.Close();

                work = string.Format("{0} {1} - SendCallback End",
                                    GetSet.ProductName, DateTime.Now);
                Trace.WriteLine(work);
            }

            catch (Exception ex)
            {
                if (!EventLog.SourceExists(GetSet.ProductName))
                    EventLog.CreateEventSource(GetSet.ProductName, "Application");

                eventLogInstaller.Source = GetSet.ProductName;
                eventLogInstaller.Log = "Application";

                work = string.Format("{0}, {1}, {2}", DateTime.Now, ex.Message, ex.StackTrace);
                eventLogInstaller.WriteEntry(work);
                Trace.WriteLine(work);
                return;
            }
        }
Posted
Comments
gggustafson 3-May-14 23:38pm    
First, since your code doesn't work, in the catch blocks just print out the ex.Message and ex.StackTrace using a MessageBox.Show. Note by returning from the catch you are not propigating the error upward. What is GetSet - I'm not familiar with it.
gmhanna 3-May-14 23:56pm    
Hi - I never knew if I should code a return in a catch, now I understand. I will be removing all the returns from my catch blocks.

GetSet is one of my classes that are just a bunch of getters and setters for the project.

This is running as a service on a server, so Windows Services are not available for a MessageBox, however for testing I have been lifting my code and pasting it into a WinForm test program.

It appears to me that the service is still bound to the port in the IP stack. I will run a NETSTAT in the morning just to verify what I'm thinking is true.

Thank you,
Glenn
gggustafson 4-May-14 0:06am    
Just to clear something up. In C# exceptions are thrown when something unexpected happens. Something like divide-by-zero, reference unassigned memory, etc. Normally exceptions indicate a serious enough error that the application should not continue execution. BUT some weenie decided to provide the try-catch-finally construct that allows programmers to bypass fatal errors. That's what you did by placing a return in your catch block. When I use a try-catch-finally block I normally throw an exception that describes the error. Retrowing the exception or throwing a new exception in the catch block causes the program to halt. That's what you want to do. So don't just remove the returns (the flow of execution will probably exit the method anyway). Rather reduce the amount of things you do in the catch block

Is this code running in a thread?
gmhanna 4-May-14 0:22am    
Thank you for clearing that up. Yes, this is running on a thread that starts with WaitForConnection, out of OnStart. Where I start the next thread is where I expected the current thread to end (ReadCallback). The code is working great for the first connection, it's just waiting for the second connection is where I'm having a problem.

Glenn
gggustafson 4-May-14 14:07pm    
First of all, the sockets implementation running on multiple threads will cause a race condition, exhibiting the behavior you noted.

Although I have not used the specific implemention found in the article, I suggest that you read the Code Project article "Simple Client-server Interactions using C#". It may get you over the hard spots. You could also Google "c# client server tutorial" or "c# client server". Although the dates of the various results may appear "old", I've used the same type of client/server implementation since the early 90's

Good luck.

1 solution

After removing the "break" in the while loop in the WaitForConnection method there is no longer a need to call the WaitForConnection method again. This resolved the problem.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900