Search code examples
c#.nettcpremoting

Register channel with known name, then check and unregister it through that known name without terminate other application channel


i had problem with application messaging, ...after some question and answer, i went to use Remoting namespace, under System.Runtime namespace...

it worked perfectly, but the matter is when application terminate with exception... if server stop in not manner, the channel i register will stay registered, ...

i dont have much knowledge over remoting or other related matter... but i checked some of things, and non didnt worked...

the article i went through done registering this way, and didnt unregister the application, and i use it in service, and seem service application host dont close just with service beign stopped...

here's my client class which is used in service applciation...

using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace Remoting
{
    public class Client
    {
        private RemotableObject remoteObject;

        /// <summary>
        /// Configure Client Class
        /// </summary>
        /// <param name="url">Something like: tcp://localhost:8080/HelloWorld</param>
        public Client(string url)
        {
            TcpChannel chan = new TcpChannel();
            ChannelServices.RegisterChannel(chan);

            remoteObject = (RemotableObject)Activator.GetObject(typeof(RemotableObject), url);
        }


        public void SetMessage(string message)
        {
            remoteObject.SetMessage(message);
        }
    }
}

as i noticed, the article give no information to the channel, so i'm wonder for unregistering it how should i find it.....

in the server APP, the article done givin host post at last

using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;

namespace Remoting
{
    public abstract class Server:IObserver
    {
        private RemotableObject remotableObject;

        /// <summary>
        /// Configure Server Class
        /// </summary>
        /// <param name="port">port number like: 8080</param>
        /// <param name="url">Object url like: HelloWorld</param>
        public Server(int port, string url)
        {
            remotableObject = new RemotableObject();

            TcpChannel channel = new TcpChannel(port);
            ChannelServices.RegisterChannel(channel);
            RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotableObject), url, WellKnownObjectMode.Singleton);

            Cache.Attach(this);
        }

        public abstract void Notify(string message);
    }
}

but, even know think i launch my application over a server that run an app with same port number, i do not want to un-register other application channels... what should i do?

BTW most issue is about the client that register a channel, with no information... how do i detect it? and unregister it, before service try to do that, and terminate with exception?

if it help, this is the error i already recieve:

Event Type: Error
Event Source: Event Reader Service
Event Category: None
Event ID: 0
Date: 8/20/2012
Time: 5:23:14 PM
User: N/A
Computer: HF-SERVER-PC
Description:
Service cannot be started. System.Runtime.Remoting.RemotingException: The channel 'tcp' is already registered. at System.Runtime.Remoting.Channels.ChannelServices.RegisterChannelInternal(IChannel chnl, Boolean ensureSecurity) at System.Runtime.Remoting.Channels.ChannelServices.RegisterChannel(IChannel chnl) at Remoting.Client..ctor(String url) at FileEventReaderService.Services.Logger.EventLogger..ctor(String source, String logName, String url) at FileEventReaderService.EventReader..ctor(String sqlServer, String instance, String integratedSecurityType, String username, String password, String dataBase) at FileEventReaderService.EventReaderService.OnStart(String[] args) at System.ServiceProcess.ServiceBase.ServiceQueuedMainCallback(Object state)

For more information, see Help and Support Center at go.microsoft.com/fwlink/….


Solution

  • In my case the problem were with multiple registering the tcp channel, in same instance, so i made a singleton class, and just set client once, and all other time i just called that instance....

    using Remoting;
    
    namespace FileEventReaderService.Services.Remotable
    {
        class SingletonClient
        {
            private static SingletonClient _instance = new SingletonClient();
            private Client _client = null;
    
            public static SingletonClient GetSingletonClient()
            {
                return _instance;
            }
    
            public Client GetClient()
            {
                return _client;
            }
    
            public void SetClientConfiguration(string url)
            {
                _client=new Client(url);
            }
        }
    }
    

    BTW, if any one need to find the process... he can use this article: http://www.timvw.be/2007/09/09/build-your-own-netstatexe-with-c/ download the demo source and use it...

    i also edit it in my own way, you can use it: (i did not changed 2 main class 'TcpTable' and 'IpHelper')

    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using System.Net.NetworkInformation;
    using System.Net;
    using System.Diagnostics;
    using System.Collections;
    using System.IO;
    
    namespace FileEventReaderUI.Services.Network
    {
        class NetworkInformation
        {
            public ListenerProcessInformation GetListenerProcessInformationByPort(int port)
            {
                string fileName;
                List<string> processModules=new List<string>();
    
                foreach (TcpRow tcpRow in ManagedIpHelper.GetExtendedTcpTable(true))
                {
                    if (tcpRow.LocalEndPoint.Port.ToString(CultureInfo.InvariantCulture).Equals(
                            port.ToString(CultureInfo.InvariantCulture))
                        && tcpRow.State==TcpState.Listen)
                    {
                        Process process = Process.GetProcessById(tcpRow.ProcessId);
                        if (process.ProcessName != "System")
                        {
                            foreach (ProcessModule processModule in process.Modules)
                            {
                                processModules.Add(processModule.FileName);
                            }
    
                            fileName = Path.GetFileName(process.MainModule.FileName);
                        }
                        else
                        {
                            //Console.WriteLine("  -- unknown component(s) --"); ProcessModules count=0
                            //Console.WriteLine("  [{0}]", "System");
                            fileName = "[System]";
                        }
    
                        return new ListenerProcessInformation(fileName
                                                              , processModules.ToArray()
                                                              , new IPEndPoint(tcpRow.LocalEndPoint.Address,
                                                                             tcpRow.LocalEndPoint.Port)
                                                              , new IPEndPoint(tcpRow.RemoteEndPoint.Address,
                                                                             tcpRow.RemoteEndPoint.Port)
                                                              , tcpRow.ProcessId
                                                              , tcpRow.State);
                    }
                }
                return null;
            }
        }
    
        #region Managed IP Helper API
    
        public class TcpTable : IEnumerable<TcpRow>
        {
            #region Private Fields
    
            private IEnumerable<TcpRow> tcpRows;
    
            #endregion
    
            #region Constructors
    
            public TcpTable(IEnumerable<TcpRow> tcpRows)
            {
                this.tcpRows = tcpRows;
            }
    
            #endregion
    
            #region Public Properties
    
            public IEnumerable<TcpRow> Rows
            {
                get { return this.tcpRows; }
            }
    
            #endregion
    
            #region IEnumerable<TcpRow> Members
    
            public IEnumerator<TcpRow> GetEnumerator()
            {
                return this.tcpRows.GetEnumerator();
            }
    
            #endregion
    
            #region IEnumerable Members
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.tcpRows.GetEnumerator();
            }
    
            #endregion
        }
    
        public class TcpRow
        {
            #region Private Fields
    
            private IPEndPoint localEndPoint;
            private IPEndPoint remoteEndPoint;
            private TcpState state;
            private int processId;
    
            #endregion
    
            #region Constructors
    
            public TcpRow(IpHelper.TcpRow tcpRow)
            {
                this.state = tcpRow.state;
                this.processId = tcpRow.owningPid;
    
                int localPort = (tcpRow.localPort1 << 8) + (tcpRow.localPort2) + (tcpRow.localPort3 << 24) + (tcpRow.localPort4 << 16);
                long localAddress = tcpRow.localAddr;
                this.localEndPoint = new IPEndPoint(localAddress, localPort);
    
                int remotePort = (tcpRow.remotePort1 << 8) + (tcpRow.remotePort2) + (tcpRow.remotePort3 << 24) + (tcpRow.remotePort4 << 16);
                long remoteAddress = tcpRow.remoteAddr;
                this.remoteEndPoint = new IPEndPoint(remoteAddress, remotePort);
            }
    
            #endregion
    
            #region Public Properties
    
            public IPEndPoint LocalEndPoint
            {
                get { return this.localEndPoint; }
            }
    
            public IPEndPoint RemoteEndPoint
            {
                get { return this.remoteEndPoint; }
            }
    
            public TcpState State
            {
                get { return this.state; }
            }
    
            public int ProcessId
            {
                get { return this.processId; }
            }
    
            #endregion
        }
    
        public static class ManagedIpHelper
        {
            #region Public Methods
    
            public static TcpTable GetExtendedTcpTable(bool sorted)
            {
                List<TcpRow> tcpRows = new List<TcpRow>();
    
                IntPtr tcpTable = IntPtr.Zero;
                int tcpTableLength = 0;
    
                if (IpHelper.GetExtendedTcpTable(tcpTable, ref tcpTableLength, sorted, IpHelper.AfInet, IpHelper.TcpTableType.OwnerPidAll, 0) != 0)
                {
                    try
                    {
                        tcpTable = Marshal.AllocHGlobal(tcpTableLength);
                        if (IpHelper.GetExtendedTcpTable(tcpTable, ref tcpTableLength, true, IpHelper.AfInet, IpHelper.TcpTableType.OwnerPidAll, 0) == 0)
                        {
                            IpHelper.TcpTable table = (IpHelper.TcpTable)Marshal.PtrToStructure(tcpTable, typeof(IpHelper.TcpTable));
    
                            IntPtr rowPtr = (IntPtr)((long)tcpTable + Marshal.SizeOf(table.length));
                            for (int i = 0; i < table.length; ++i)
                            {
                                tcpRows.Add(new TcpRow((IpHelper.TcpRow)Marshal.PtrToStructure(rowPtr, typeof(IpHelper.TcpRow))));
                                rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(IpHelper.TcpRow)));
                            }
                        }
                    }
                    finally
                    {
                        if (tcpTable != IntPtr.Zero)
                        {
                            Marshal.FreeHGlobal(tcpTable);
                        }
                    }
                }
    
                return new TcpTable(tcpRows);
            }
    
            #endregion
        }
    
        #endregion
    
        #region P/Invoke IP Helper API
    
        /// <summary>
        /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366073.aspx"/>
        /// </summary>
        public static class IpHelper
        {
            #region Public Fields
    
            public const string DllName = "iphlpapi.dll";
            public const int AfInet = 2;
    
            #endregion
    
            #region Public Methods
    
            /// <summary>
            /// <see cref="http://msdn2.microsoft.com/en-us/library/aa365928.aspx"/>
            /// </summary>
            [DllImport(IpHelper.DllName, SetLastError = true)]
            public static extern uint GetExtendedTcpTable(IntPtr tcpTable, ref int tcpTableLength, bool sort, int ipVersion, TcpTableType tcpTableType, int reserved);
    
            #endregion
    
            #region Public Enums
    
            /// <summary>
            /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366386.aspx"/>
            /// </summary>
            public enum TcpTableType
            {
                BasicListener,
                BasicConnections,
                BasicAll,
                OwnerPidListener,
                OwnerPidConnections,
                OwnerPidAll,
                OwnerModuleListener,
                OwnerModuleConnections,
                OwnerModuleAll,
            }
    
            #endregion
    
            #region Public Structs
    
            /// <summary>
            /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366921.aspx"/>
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            public struct TcpTable
            {
                public uint length;
                public TcpRow row;
            }
    
            /// <summary>
            /// <see cref="http://msdn2.microsoft.com/en-us/library/aa366913.aspx"/>
            /// </summary>
            [StructLayout(LayoutKind.Sequential)]
            public struct TcpRow
            {
                public TcpState state;
                public uint localAddr;
                public byte localPort1;
                public byte localPort2;
                public byte localPort3;
                public byte localPort4;
                public uint remoteAddr;
                public byte remotePort1;
                public byte remotePort2;
                public byte remotePort3;
                public byte remotePort4;
                public int owningPid;
            }
    
            #endregion
        }
    
        #endregion
    }
    

    and the Entity class i use to fill ...

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Net;
    using System.Net.NetworkInformation;
    using System.Text;
    
    namespace FileEventReaderUI.Services.Network
    {
        class ListenerProcessInformation
        {
            private string _fileName;
            private string[] _processModules;
            private IPEndPoint _localEndPoint;
            private IPEndPoint _remoteEndPoint;
            private int _processId;
            private TcpState _state;
    
            public ListenerProcessInformation(string fileName, string[] processModules, IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, int processId, TcpState state)
            {
                _fileName = fileName;
                _processModules = processModules;
                _localEndPoint = localEndPoint;
                _remoteEndPoint = remoteEndPoint;
                _processId = processId;
                _state = state;
            }
    
            public string FileName
            {
                get { return _fileName; }
            }
    
            public string[] ProcessModules
            {
                get { return _processModules; }
            }
    
            public IPEndPoint LocalEndPoint
            {
                get { return _localEndPoint; }
            }
    
            public IPEndPoint RemoteEndPoint
            {
                get { return _remoteEndPoint; }
            }
    
            public int ProcessId
            {
                get { return _processId; }
            }
    
            public TcpState State
            {
                get { return _state; }
            }
        }
    }