欧美大屁股bbbbxxxx,狼人大香伊蕉国产www亚洲,男ji大巴进入女人的视频小说,男人把ji大巴放进女人免费视频,免费情侣作爱视频

歡迎來到入門教程網(wǎng)!

C#教程

當(dāng)前位置:主頁 > 軟件編程 > C#教程 >

C# NetRemoting實(shí)現(xiàn)雙向通信

來源:本站原創(chuàng)|時(shí)間:2020-01-10|欄目:C#教程|點(diǎn)擊: 次

閑來無事想玩玩雙向通信,實(shí)現(xiàn)類似QQ的互發(fā)消息的功能。于是乎開始學(xué)習(xí).Net Remoting.

.Net Remoting 是由客戶端通過Remoting,訪問通道以獲得服務(wù)端對象,再通過代理解析為客戶端對象來實(shí)現(xiàn)通信的。也就是說對象是由服務(wù)端創(chuàng)建的。

先上代碼

首先是ICommand庫

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>
    /// 加法運(yùn)算
    /// </summary>
    /// <param name="x1">參數(shù)1</param>
    /// <param name="x2">參數(shù)2</param>
    /// <returns></returns>
    string SUM(int x1, int x2);
    /// <summary>
    /// 獲取服務(wù)端事件列表
    /// </summary>
    Delegate[] GetServerEventList();
    /// <summary>
    /// 發(fā)送消息
    /// </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>
  /// 客戶端發(fā)送消息
  /// </summary>
  /// <param name="info">信息</param>
  /// <param name="toName">發(fā)送給誰,""表示所有人,null表示沒有接收服務(wù)器自己接收,其他表示指定某人</param>
  public delegate void SendHandler(object info, string toName);
  /// <summary>
  /// 客戶端接收消息
  /// </summary>
  /// <param name="info">信息</param>
  /// <param name="toName">發(fā)送給誰,""表示所有人,null表示沒有接收服務(wù)器自己接收,其他表示指定某人</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;
  } 
}

第一個(gè)類就是定義一些接口,和一些委托,沒有實(shí)質(zhì)性的東西。

第二個(gè)類是定義了上一個(gè)接口類中的ToClient的事件和方法,作用之后會講到。

然后就是集成ICommand接口的實(shí)質(zhì)性的數(shù)據(jù)類

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

namespace NetRemoting
{
  public class RemotingObject : MarshalByRefObject, IRemotingObject
  {
    /// <summary>
    /// 發(fā)送事件
    /// </summary>
    public event SendHandler ClientToServer
    {
      add { _send += value; }
      remove { _send -= value; }
    }
    /// <summary>
    /// 接收消息事件
    /// </summary>
    public event ReceiveHandler ServerToClient;
    /// <summary>
    /// 發(fā)送事件
    /// </summary>
    public event UserChangedHandler Login
    {
      add { _login += value; }
      remove { _login -= value; }
    }
    /// <summary>
    /// 發(fā)送事件
    /// </summary>
    public event UserChangedHandler Exit
    {
      add { _exit += value; }
      remove { _exit -= value; }
    }
    /// <summary>
    /// 加法運(yùn)算
    /// </summary>
    /// <param name="x1">參數(shù)1</param>
    /// <param name="x2">參數(shù)2</param>
    /// <returns></returns>
    public string SUM(int x1, int x2)
    {
      return x1 + "+" + x2 + "=" + (x1 + x2);
    }
    /// <summary>
    /// 綁定服務(wù)端向客戶端發(fā)送消息的事件方法
    /// </summary>
    /// <param name="receive">接收事件</param>
    public Delegate[] GetServerEventList()
    {
      return this.ServerToClient.GetInvocationList();
    }
    /// <summary>
    /// 發(fā)送消息
    /// </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>();
  }
}

該類集成了MarshalByRefObject

由于Remoting傳遞的對象是以引用的方式,因此所傳遞的遠(yuǎn)程對象類必須繼承MarshalByRefObject。MSDN對MarshalByRefObject的說明是:MarshalByRefObject 是那些通過使用代理交換消息來跨越應(yīng)用程序域邊界進(jìn)行通信的對象的基類。不是從 MarshalByRefObject 繼承的對象會以隱式方式按值封送。當(dāng)遠(yuǎn)程應(yīng)用程序引用一個(gè)按值封送的對象時(shí),將跨越遠(yuǎn)程處理邊界傳遞該對象的副本。因?yàn)槟M褂么矸椒ǘ皇歉北痉椒ㄟM(jìn)行通信,因此需要繼承MarshallByRefObject。

該類主要是定義了一些方法用于客戶端觸發(fā)事件,ToServer,ToClient,ToLogin,ToExit以及一些事件,客戶端發(fā)向服務(wù)端的事件,和服務(wù)端發(fā)向客戶端的事件。

_nameHash 只是記錄有哪些用戶登錄了。

接下去就是客戶端和服務(wù)端了。

首先服務(wù)端:

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 轉(zhuǎn)換為具有指定 URI 的 System.Runtime.Remoting.ObjRef 類的實(shí)例。
       ObjRef :存儲生成代理以與遠(yuǎn)程對象通信所需要的所有信息。*/
      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>
    /// 發(fā)送消息到客戶端
    /// </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()
    {
      //設(shè)置反序列化級別 
      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;


  }
}

然后客戶端:

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
      {
        //設(shè)置反序列化級別 
        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>
    /// 發(fā)送
    /// </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;

  }
}

服務(wù)端實(shí)現(xiàn)步驟:

1、注冊通道

要跨越應(yīng)用程序域進(jìn)行通信,必須實(shí)現(xiàn)通道。如前所述,Remoting提供了IChannel接口,分別包含TcpChannel和HttpChannel兩種類型的通道。這兩種類型除了性能和序列化數(shù)據(jù)的格式不同外,實(shí)現(xiàn)的方式完全一致,因此下面我們就以TcpChannel為例。

注冊TcpChannel,首先要在項(xiàng)目中添加引用“System.Runtime.Remoting”,然后using名字空間:System.Runtime.Remoting.Channel.Tcp。代碼如下:

TcpChannel channel = new TcpChannel(8022);
ChannelServices.RegisterChannel(channel);

在實(shí)例化通道對象時(shí),將端口號作為參數(shù)傳遞。然后再調(diào)用靜態(tài)方法RegisterChannel()來注冊該通道對象即可。

2、注冊遠(yuǎn)程對象

注冊了通道后,要能激活遠(yuǎn)程對象,必須在通道中注冊該對象。根據(jù)激活模式的不同,注冊對象的方法也不同。

(1) SingleTon模式

對于WellKnown對象,可以通過靜態(tài)方法RemotingConfiguration.RegisterWellKnownServiceType()來實(shí)現(xiàn):

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

(2)SingleCall模式

注冊對象的方法基本上和SingleTon模式相同,只需要將枚舉參數(shù)WellKnownObjectMode改為SingleCall就可以了。

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

客戶端實(shí)現(xiàn)步驟:

1、注冊通道:

TcpChannel channel = new TcpChannel();
ChannelServices.RegisterChannel(channel);

注意在客戶端實(shí)例化通道時(shí),是調(diào)用的默認(rèn)構(gòu)造函數(shù),即沒有傳遞端口號。事實(shí)上,這個(gè)端口號是缺一不可的,只不過它的指定被放在后面作為了Uri的一部分。

2、獲得遠(yuǎn)程對象。

與服務(wù)器端相同,不同的激活模式?jīng)Q定了客戶端的實(shí)現(xiàn)方式也將不同。不過這個(gè)區(qū)別僅僅是WellKnown激活模式和客戶端激活模式之間的區(qū)別,而對于SingleTon和SingleCall模式,客戶端的實(shí)現(xiàn)完全相同。

(1) WellKnown激活模式

要獲得服務(wù)器端的知名遠(yuǎn)程對象,可通過Activator進(jìn)程的GetObject()方法來獲得:

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

首先以WellKnown模式激活,客戶端獲得對象的方法是使用GetObject()。其中參數(shù)第一個(gè)是遠(yuǎn)程對象的類型。第二個(gè)參數(shù)就是服務(wù)器端的uri。如果是http通道,自然是用http://localhost:8022/ServiceMessage了。因?yàn)槲沂怯帽镜貦C(jī),所以這里是localhost,你可以用具體的服務(wù)器IP地址來代替它。端口必須和服務(wù)器端的端口一致。后面則是服務(wù)器定義的遠(yuǎn)程對象服務(wù)名,即ApplicationName屬性的內(nèi)容。

//設(shè)置反序列化級別 
        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);

從上述代碼中可以看到注冊方式有所變化,那是因?yàn)榭蛻舳俗苑?wù)端的事件時(shí)會報(bào)錯(cuò)“不允許類型反序列化”。

還有一個(gè)需要注意的是:

ObjRef objRef = RemotingServices.Marshal(_remotingObject, "SumMessage");
//RemotingConfiguration.RegisterWellKnownServiceType(typeof(RemotingObject), "SumMessage", WellKnownObjectMode.Singleton);
//調(diào)用系統(tǒng)自動創(chuàng)建,導(dǎo)致拿不到_remotingObject對象的實(shí)例化,這樣后期綁定事件就無法操作下去了,當(dāng)然也可以直接靜態(tài)事件綁定,這樣就不需要手動實(shí)例化對象了

通過該方法手動創(chuàng)建_remotingObject這個(gè)對象的實(shí)例化。

然后之前講到了一個(gè)SwapObject這個(gè)類,這個(gè)類的作用是事件交換。

 

_remotingObject.ServerToClient +=方法();
//這樣因?yàn)檫@個(gè)方法是客戶端的,服務(wù)端無法調(diào)用,所以需要一個(gè)中間轉(zhuǎn)換的
 SwapObject swap = new SwapObject();//先創(chuàng)建一個(gè)Swap對象
 _remotingObject.ServerToClient += swap.ToClient;//然后服務(wù)端事件發(fā)信息給swap,然后swap再通過事件發(fā)消息給客戶端,swap是客戶端創(chuàng)建的所以可以發(fā)送,而swap是服務(wù)端的類,所以服務(wù)端也能識別,swap起到了中間過渡的作用
 swap.SwapServerToClient +=方法();

以上是兩天.Net Remoting的學(xué)習(xí)結(jié)果。

最后附上源碼:NetRemoting_jb51.rar

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。

上一篇:C#無損轉(zhuǎn)換Image為Icon的方法

欄    目:C#教程

下一篇:C# 中如何取絕對值函數(shù)

本文標(biāo)題:C# NetRemoting實(shí)現(xiàn)雙向通信

本文地址:http://mengdiqiu.com.cn/a1/C_jiaocheng/5808.html

網(wǎng)頁制作CMS教程網(wǎng)絡(luò)編程軟件編程腳本語言數(shù)據(jù)庫服務(wù)器

如果侵犯了您的權(quán)利,請與我們聯(lián)系,我們將在24小時(shí)內(nèi)進(jìn)行處理、任何非本站因素導(dǎo)致的法律后果,本站均不負(fù)任何責(zé)任。

聯(lián)系QQ:835971066 | 郵箱:835971066#qq.com(#換成@)

Copyright © 2002-2020 腳本教程網(wǎng) 版權(quán)所有