c# - 使用已知名称注册 channel ,然后通过该已知名称检查和注销它而不终止其他应用程序 channel

标签 c# .net tcp remoting

我在应用程序消息传递方面遇到问题,...经过一些问答,我开始使用 System.Runtime 命名空间下的 Remoting 命名空间...

它工作得很好,但问题是当应用程序异常终止时...... 如果服务器未正常停止,我注册的 channel 将保持注册状态,...

我对远程处理或其他相关问题了解不多... 但我检查了一些东西,但没有奏效......

我阅读的文章以这种方式完成了注册,并没有注销应用程序,我在服务中使用它,似乎服务应用程序主机不会在服务停止时关闭...

这是我在服务应用程序中使用的客户端类...

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);
        }
    }
}

正如我所注意到的,这篇文章没有给 channel 任何信息,所以我想知道要取消注册它我应该如何找到它......

在服务端APP中,文章最后完成了givin host post

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);
    }
}

但是,即使知道我认为我在运行具有相同端口号的应用程序的服务器上启动我的应用程序,我也不想注销其他应用程序 channel ...我应该怎么做?

顺便说一句,大多数问题是关于注册 channel 的客户端,没有任何信息...我如何检测到它?并在服务尝试这样做之前注销它,并以异常终止?

如果有帮助,这是我已经收到的错误:

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/….

最佳答案

在我的例子中,问题是在同一个实例中多次注册 tcp channel ,所以我做了一个单例类,只设置了一次客户端,其他时间我只是调用了那个实例....

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);
        }
    }
}

顺便说一句,如果有人需要找到进程......他可以使用这篇文章: http://www.timvw.be/2007/09/09/build-your-own-netstatexe-with-c/下载演示源并使用它...

我也用我自己的方式编辑它,你可以使用它:(我没有改变2个主类'TcpTable'和'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
}

以及我用来填充的实体类......

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; }
        }
    }
}

关于c# - 使用已知名称注册 channel ,然后通过该已知名称检查和注销它而不终止其他应用程序 channel ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12039195/

相关文章:

c# - 这个冒号是什么(:) mean?

regex.replace() 中的 C# 多个模式

sockets - 是否可以将 UDP 与 socket.io 一起使用?

c++ - 使用 tcp 套接字复制损坏的管道错误

c# - 将字符串解析为对象

c# - SpinLock 并没有真正进行忙循环等待?

c# - Server.MapPath 在当前上下文中不存在

.net - 如果其中一个作业出现异常,Async.Parallel 是否会取消所有作业?

c# - 将变量值和输出从 PL/SQL 代码块返回到 C#

c# - 如何强行关闭 TcpListener