search
HomeBackend DevelopmentC#.Net TutorialC#NetRemoting implements sample code sharing for two-way communication

This article mainly introduces C# NetRemoting realizes two-way communication. .Net Remoting is used by the client to access the channel to obtain the server through Remotingobject, and then resolve it into a client object through the proxy to achieve communication

I have nothing to do and want to play with two-way communication, achieving something like QQ's function of sending messages to each other. So I started to learn .Net Remoting.

.Net Remoting is implemented by the client accessing the channel to obtain the server object through Remoting, and then parsing it into the client object through the proxy. Communication. In other words, the object is created by the server.

The first is the ICommand library

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ICommand
{
  public interface IRemotingObject
  {
    event SendHandler ClientToServer;
    event ReceiveHandler ServerToClient;
    event UserChangedHandler Login;
    event UserChangedHandler Exit;
    /// <summary>
    /// 加法运算
    /// </summary>
    /// <param name="x1">参数1</param>
    /// <param name="x2">参数2</param>
    /// <returns></returns>
    string SUM(int x1, int x2);
    /// <summary>
    /// 获取服务端事件列表
    /// </summary>
    Delegate[] GetServerEventList();
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="info"></param>
    /// <param name="toName"></param>
    void ToServer(object info, string toName);
    /// <summary>
    /// 接受信息
    /// </summary>
    /// <param name="info"></param>
    /// <param name="toName"></param>
    void ToClient(object info, string toName);
    void ToLogin(string name);
    void ToExit(string name);
  }
  /// <summary>
  /// 客户端发送消息
  /// </summary>
  /// <param name="info">信息</param>
  /// <param name="toName">发送给谁,""表示所有人,null表示没有接收服务器自己接收,其他表示指定某人</param>
  public delegate void SendHandler(object info, string toName);
  /// <summary>
  /// 客户端接收消息
  /// </summary>
  /// <param name="info">信息</param>
  /// <param name="toName">发送给谁,""表示所有人,null表示没有接收服务器自己接收,其他表示指定某人</param>
  public delegate void ReceiveHandler(object info, string toName);
  /// <summary>
  /// 用户信息事件
  /// </summary>
  /// <param name="name">用户名</param>
  public delegate void UserChangedHandler(string name);
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ICommand
{
  public class SwapObject : MarshalByRefObject
  {

    public event ReceiveHandler SwapServerToClient 
    {
      add { _receive += value; }
      remove { _receive -= value; }
    }
    /// <summary>
    /// 接受信息
    /// </summary>
    /// <param name="info"></param>
    /// <param name="toName"></param>
    public void ToClient(object info, string toName)
    {
      if (_receive != null)
        _receive(info, toName);
    }
    //无限生命周期 
    public override object InitializeLifetimeService()
    {
      return null;
    }

    private ReceiveHandler _receive;
  } 
}

The first class is to define some

The interface

, and some delegates, have nothing substantial. The second class defines the ToClient events and methods in the previous interface class, which will be discussed later. ##Then there is the substantive data class that integrates the ICommand interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICommand;

namespace NetRemoting
{
  public class RemotingObject : MarshalByRefObject, IRemotingObject
  {
    /// <summary>
    /// 发送事件
    /// </summary>
    public event SendHandler ClientToServer
    {
      add { _send += value; }
      remove { _send -= value; }
    }
    /// <summary>
    /// 接收消息事件
    /// </summary>
    public event ReceiveHandler ServerToClient;
    /// <summary>
    /// 发送事件
    /// </summary>
    public event UserChangedHandler Login
    {
      add { _login += value; }
      remove { _login -= value; }
    }
    /// <summary>
    /// 发送事件
    /// </summary>
    public event UserChangedHandler Exit
    {
      add { _exit += value; }
      remove { _exit -= value; }
    }
    /// <summary>
    /// 加法运算
    /// </summary>
    /// <param name="x1">参数1</param>
    /// <param name="x2">参数2</param>
    /// <returns></returns>
    public string SUM(int x1, int x2)
    {
      return x1 + "+" + x2 + "=" + (x1 + x2);
    }
    /// <summary>
    /// 绑定服务端向客户端发送消息的事件方法
    /// </summary>
    /// <param name="receive">接收事件</param>
    public Delegate[] GetServerEventList()
    {
      return this.ServerToClient.GetInvocationList();
    }
    /// <summary>
    /// 发送消息
    /// </summary>
    /// <param name="info"></param>
    /// <param name="toName"></param>
    public void ToServer(object info, string toName)
    {
      if (_send != null)
        _send(info, toName);
    }
    /// <summary>
    /// 接收消息
    /// </summary>
    /// <param name="info"></param>
    /// <param name="toName"></param>
    public void ToClient(object info, string toName)
    {
      if (_receive != null)
        _receive(info, toName);
    }
    /// <summary>
    /// 登录
    /// </summary>
    /// <param name="name">用户名</param>
    public void ToLogin(string name)
    {
      if (!_nameHash.Contains(name))
      {
        _nameHash.Add(name);
        if (_login != null)
          _login(name);
      }
      else
      { throw new Exception("用户已存在"); }
    }
    /// <summary>
    /// 退出
    /// </summary>
    /// <param name="name">用户名</param>
    public void ToExit(string name)
    {
      if (_nameHash.Contains(name))
      {
        _nameHash.Remove(name);
        if (_exit != null)
          _exit(name);
      }
    }

    private SendHandler _send;
    private ReceiveHandler _receive;
    private UserChangedHandler _login;
    private UserChangedHandler _exit;
    private HashSet<string> _nameHash = new HashSet<string>();
  }
}

This class integrates MarshalByRefObject

Since the object passed by Remoting is

referenced

, so The passed remote object class must

Inherit

MarshalByRefObject. MSDN's description of MarshalByRefObject is: MarshalByRefObject is the base class for objects that communicate across application domain boundaries by using proxies. Objects that do not inherit from MarshalByRefObject. Marshaling by value is implicit. When a remote application references an object that is marshaled by value, a copy of the object is passed across the remoting boundary, which is required because you want to communicate using proxy methods instead of copy methods. Inherits MarshallByRefObject. This class mainly defines some methods for the client to trigger events, ToServer, ToClient, ToLogin, ToExit and some events, events sent by the client to the server, and events sent by the server to the client. Event. ##_nameHash just records which

users have logged in

. The next step is the client and server

. End:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using NetRemoting;
using System.Collections;
using System.Runtime.Serialization.Formatters;
using ICommand;

namespace NetRemotingServer
{
  public partial class Server : Form
  {
    public Server()
    {
      InitializeComponent();
      Initialize();
    }
    /// <summary>
    /// 注册通道
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Server_Load(object sender, EventArgs e)
    {

      ChannelServices.RegisterChannel(_channel, false);
      //RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject), "SumMessage", WellKnownObjectMode.Singleton); //a方案
      /*将给定的 System.MarshalByRefObject 转换为具有指定 URI 的 System.Runtime.Remoting.ObjRef 类的实例。
       ObjRef :存储生成代理以与远程对象通信所需要的所有信息。*/
      ObjRef objRef = RemotingServices.Marshal(_remotingObject, "SumMessage");//b方案
      _remotingObject.ClientToServer += (info, toName) =>
      {
        rxtInfo.Invoke((MethodInvoker)(() => { rxtInfo.AppendText(info.ToString() + "\r\n"); }));
        SendToClient(info, toName);
      };
      _remotingObject.Login += (name) =>
      {
        rxtInfo.Invoke((MethodInvoker)(() => { rxtInfo.AppendText(name + " 登录" + "\r\n"); }));
      };
      _remotingObject.Exit += (name) =>
      {
        rxtInfo.Invoke((MethodInvoker)(() => { rxtInfo.AppendText(name + " 退出" + "\r\n"); }));
      };
    }
    /// <summary>
    /// 注销通道
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Server_FormClosing(object sender, FormClosingEventArgs e)
    {
      if (_channel != null)
      {
        _channel.StopListening(null);
        ChannelServices.UnregisterChannel(_channel);
      }
    }
    /// <summary>
    /// 广播消息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnSend_Click(object sender, EventArgs e)
    {
      SendToClient(txtSend.Text, txtName.Text);
    }
    /// <summary>
    /// 发送消息到客户端
    /// </summary>
    /// <param name="info"></param>
    /// <param name="toName"></param>
    private void SendToClient(object info, string toName)
    {
      //foreach (var v in _remotingObject.GetServerEventList())
      //{
      //  try
      //  {
      //    ReceiveHandler receive = (ReceiveHandler)v;
      //    receive.BeginInvoke(info, toName, null, null);
      //  }
      //  catch
      //  { }
      // }
      _remotingObject.ToClient(txtSend.Text, txtName.Text);
    }
    /// <summary>
    /// 初始化
    /// </summary>
    private void Initialize()
    {
      //设置反序列化级别 
      BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
      BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
      serverProvider.TypeFilterLevel = TypeFilterLevel.Full;//支持所有类型的反序列化,级别很高 
      IDictionary idic = new Dictionary<string, string>();
      idic["name"] = "serverHttp";
      idic["port"] = "8022";
      _channel = new HttpChannel(idic, clientProvider, serverProvider);
      _remotingObject = new RemotingObject();
    }

    HttpChannel _channel;
    private RemotingObject _remotingObject;


  }
}
Then client:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using ICommand;
using System.Runtime.Serialization.Formatters;
using System.Collections;

namespace NetRemotingClient
{
  public partial class Client : Form
  {
    public Client()
    {
      InitializeComponent();
    }
    /// <summary>
    /// 注册通道
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Client_Load(object sender, EventArgs e)
    {
      try
      {
        //设置反序列化级别 
        BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
        BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
        serverProvider.TypeFilterLevel = TypeFilterLevel.Full;//支持所有类型的反序列化,级别很高 
        //信道端口 
        IDictionary idic = new Dictionary<string, string>();
        idic["name"] = "clientHttp";
        idic["port"] = "0";
        HttpChannel channel = new HttpChannel(idic, clientProvider, serverProvider);
        ChannelServices.RegisterChannel(channel, false);
        _remotingObject = (IRemotingObject)Activator.GetObject(typeof(IRemotingObject), "http://localhost:8022/SumMessage");
        //_remotingObject.ServerToClient += (info, toName) => { rtxMessage.AppendText(info + "\r\n"); };
        SwapObject swap = new SwapObject();
        _remotingObject.ServerToClient += swap.ToClient;
        swap.SwapServerToClient += (info, toName) =>
        {
          rtxMessage.Invoke((MethodInvoker)(() =>
        {
          if (toName == txtLogin.Text || toName == "")
            rtxMessage.AppendText(info + "\r\n");
        }));
        };
      }
      catch (Exception ex)
      { MessageBox.Show(ex.Message); }
    }
    /// <summary>
    /// 登录
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnLogin_Click(object sender, EventArgs e)
    {
      try
      {
        if (txtLogin.Text == "")
          throw new Exception("用户名不得为空");
        _remotingObject.ToLogin(txtLogin.Text);
      }
      catch (Exception ex)
      {
        MessageBox.Show(ex.Message);
      }
    }
    /// <summary>
    /// 退出
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Client_FormClosing(object sender, FormClosingEventArgs e)
    {
      try
      {
        _remotingObject.ToExit(txtLogin.Text);
      }
      catch
      { }
    }
    /// <summary>
    /// 发送
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btnSend_Click(object sender, EventArgs e)
    {
      //rtxMessage.AppendText(_remotingObject.SUM(2, 4) + "\r\n");
      _remotingObject.ToServer(txtSend.Text, txtName.Text);
    }


    private IRemotingObject _remotingObject;

  }
}

Server implementation steps:

1. Registration channel

To communicate across application domains, channels must be implemented. As mentioned before, Remoting provides the IChannel interface, which contains two types of channels: TcpChannel and HttpChannel. Except for the different performance and format of serialized data, these two types are implemented in exactly the same way, so below we will take TcpChannel as an example.

To register TcpChannel, first add the reference "System.Runtime.Remoting" to the project, and then use the namespace: System.Runtime.Remoting.Channel.Tcp. The code is as follows:

TcpChannel channel = new TcpChannel(8022);
ChannelServices.RegisterChannel(channel);
When instantiating the channel object, pass the port number as a parameter. Then call the static

method RegisterChannel() to register the channel object.

2. Register the remote object

After registering the channel, in order to activate the remote object, the object must be registered in the channel. Depending on the activation mode, the methods for registering objects are different.

(1) SingleTon mode

For the WellKnown object, it can be implemented through the static method RemotingConfiguration.RegisterWellKnownServiceType():

RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(ServerRemoteObject.ServerObject),
        "ServiceMessage",WellKnownObjectMode.SingleTon);

( 2)SingleCall mode

The method of registering an object is basically the same as the SingleTon mode. You only need to change the enumeration parameter WellKnownObjectMode to SingleCall.

RemotingConfiguration.RegisterWellKnownServiceType(
        typeof(ServerRemoteObject.ServerObject),
        "ServiceMessage",WellKnownObjectMode.SingleCall);

Client implementation

Steps:


1. Registration channel:

TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel);
Note that when the client instantiates the channel, the default constructor

is called, that is, the port number is not passed. In fact, this port number is indispensable, but its specification is placed later as part of the Uri.

2. Obtain the remote object

.

Same as the server side, different activation modes determine how the client is implemented. However, this difference is only between WellKnown activation mode and client activation mode. For SingleTon and SingleCall modes, the client implementation is exactly the same.

(1) WellKnown activation mode

To obtain the well-known remote object on the server side, you can obtain it through the GetObject() method of the Activator process:

ServerRemoteObject.ServerObject serverObj = (ServerRemoteObject.ServerObject)Activator.GetObject(
       typeof(ServerRemoteObject.ServerObject), "tcp://localhost:8080/ServiceMessage");

首先以WellKnown模式激活,客户端获得对象的方法是使用GetObject()。其中参数第一个是远程对象的类型。第二个参数就是服务器端的uri。如果是http通道,自然是用http://localhost:8022/ServiceMessage了。因为我是用本地机,所以这里是localhost,你可以用具体的服务器IP地址来代替它。端口必须和服务器端的端口一致。后面则是服务器定义的远程对象服务名,即ApplicationName属性的内容。

//设置反序列化级别 
        BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();
        BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider();
        serverProvider.TypeFilterLevel = TypeFilterLevel.Full;//支持所有类型的反序列化,级别很高 
        //信道端口 
        IDictionary idic = new Dictionary<string, string>();
        idic["name"] = "clientHttp";
        idic["port"] = "0";
        HttpChannel channel = new HttpChannel(idic, clientProvider, serverProvider);

从上述代码中可以看到注册方式有所变化,那是因为客户端注册服务端的事件时会报错“不允许类型反序列化”。

还有一个需要注意的是:

ObjRef objRef = RemotingServices.Marshal(_remotingObject, "SumMessage");
//RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject), "SumMessage", WellKnownObjectMode.Singleton);
//调用系统自动创建,导致拿不到_remotingObject对象的实例化,这样后期绑定事件就无法操作下去了,当然也可以直接静态事件绑定,这样就不需要手动实例化对象了

通过该方法手动创建_remotingObject这个对象的实例化。

然后之前讲到了一个SwapObject这个类,这个类的作用是事件交换。

_remotingObject.ServerToClient +=方法();
//这样因为这个方法是客户端的,服务端无法调用,所以需要一个中间转换的
 SwapObject swap = new SwapObject();//先创建一个Swap对象
 _remotingObject.ServerToClient += swap.ToClient;
 //然后服务端事件发信息给swap,然后swap再通过事件发消息给客户端,swap是客户端创建的所以可以发送,而swap是服务端的类,所以服务端也能识别,swap起到了中间过渡的作用
 swap.SwapServerToClient +=方法();

The above is the detailed content of C#NetRemoting implements sample code sharing for two-way communication. For more information, please follow other related articles on the PHP Chinese website!

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Developing with C# .NET: A Practical Guide and ExamplesDeveloping with C# .NET: A Practical Guide and ExamplesMay 12, 2025 am 12:16 AM

C# and .NET provide powerful features and an efficient development environment. 1) C# is a modern, object-oriented programming language that combines the power of C and the simplicity of Java. 2) The .NET framework is a platform for building and running applications, supporting multiple programming languages. 3) Classes and objects in C# are the core of object-oriented programming. Classes define data and behaviors, and objects are instances of classes. 4) The garbage collection mechanism of .NET automatically manages memory to simplify the work of developers. 5) C# and .NET provide powerful file operation functions, supporting synchronous and asynchronous programming. 6) Common errors can be solved through debugger, logging and exception handling. 7) Performance optimization and best practices include using StringBuild

C# .NET: Understanding the Microsoft .NET FrameworkC# .NET: Understanding the Microsoft .NET FrameworkMay 11, 2025 am 12:17 AM

.NETFramework is a cross-language, cross-platform development platform that provides a consistent programming model and a powerful runtime environment. 1) It consists of CLR and FCL, which manages memory and threads, and FCL provides pre-built functions. 2) Examples of usage include reading files and LINQ queries. 3) Common errors involve unhandled exceptions and memory leaks, and need to be resolved using debugging tools. 4) Performance optimization can be achieved through asynchronous programming and caching, and maintaining code readability and maintainability is the key.

The Longevity of C# .NET: Reasons for its Enduring PopularityThe Longevity of C# .NET: Reasons for its Enduring PopularityMay 10, 2025 am 12:12 AM

Reasons for C#.NET to remain lasting attractive include its excellent performance, rich ecosystem, strong community support and cross-platform development capabilities. 1) Excellent performance and is suitable for enterprise-level application and game development; 2) The .NET framework provides a wide range of class libraries and tools to support a variety of development fields; 3) It has an active developer community and rich learning resources; 4) .NETCore realizes cross-platform development and expands application scenarios.

Mastering C# .NET Design Patterns: From Singleton to Dependency InjectionMastering C# .NET Design Patterns: From Singleton to Dependency InjectionMay 09, 2025 am 12:15 AM

Design patterns in C#.NET include Singleton patterns and dependency injection. 1.Singleton mode ensures that there is only one instance of the class, which is suitable for scenarios where global access points are required, but attention should be paid to thread safety and abuse issues. 2. Dependency injection improves code flexibility and testability by injecting dependencies. It is often used for constructor injection, but it is necessary to avoid excessive use to increase complexity.

C# .NET in the Modern World: Applications and IndustriesC# .NET in the Modern World: Applications and IndustriesMay 08, 2025 am 12:08 AM

C#.NET is widely used in the modern world in the fields of game development, financial services, the Internet of Things and cloud computing. 1) In game development, use C# to program through the Unity engine. 2) In the field of financial services, C#.NET is used to develop high-performance trading systems and data analysis tools. 3) In terms of IoT and cloud computing, C#.NET provides support through Azure services to develop device control logic and data processing.

C# .NET Framework vs. .NET Core/5/6: What's the Difference?C# .NET Framework vs. .NET Core/5/6: What's the Difference?May 07, 2025 am 12:06 AM

.NETFrameworkisWindows-centric,while.NETCore/5/6supportscross-platformdevelopment.1).NETFramework,since2002,isidealforWindowsapplicationsbutlimitedincross-platformcapabilities.2).NETCore,from2016,anditsevolutions(.NET5/6)offerbetterperformance,cross-

The Community of C# .NET Developers: Resources and SupportThe Community of C# .NET Developers: Resources and SupportMay 06, 2025 am 12:11 AM

The C#.NET developer community provides rich resources and support, including: 1. Microsoft's official documents, 2. Community forums such as StackOverflow and Reddit, and 3. Open source projects on GitHub. These resources help developers improve their programming skills from basic learning to advanced applications.

The C# .NET Advantage: Features, Benefits, and Use CasesThe C# .NET Advantage: Features, Benefits, and Use CasesMay 05, 2025 am 12:01 AM

The advantages of C#.NET include: 1) Language features, such as asynchronous programming simplifies development; 2) Performance and reliability, improving efficiency through JIT compilation and garbage collection mechanisms; 3) Cross-platform support, .NETCore expands application scenarios; 4) A wide range of practical applications, with outstanding performance from the Web to desktop and game development.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

WebStorm Mac version

WebStorm Mac version

Useful JavaScript development tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

DVWA

DVWA

Damn Vulnerable Web App (DVWA) is a PHP/MySQL web application that is very vulnerable. Its main goals are to be an aid for security professionals to test their skills and tools in a legal environment, to help web developers better understand the process of securing web applications, and to help teachers/students teach/learn in a classroom environment Web application security. The goal of DVWA is to practice some of the most common web vulnerabilities through a simple and straightforward interface, with varying degrees of difficulty. Please note that this software