程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 利用WCF的P2P共享剪貼板上的數據

利用WCF的P2P共享剪貼板上的數據

編輯:關於.NET

WCF與P2P

WCF是用來實現數據通信的,這篇文章中。我將帶領大家進入WCF的P2P的世界。通過一個實例,說明WCF中使用P2P。

首先讓我們了解一下什麼是P2P。詳細見:P2P。這裡根據我的理解,結合WCF簡單的敘述一下。一般使用WCF,客戶端與客戶端交互都要使用一個服務端作為中間站。客戶端將數據傳遞給服務端,服務端再轉發給其他的客戶端。很明顯,這顯然加重了服務端的負擔。P2P是解決這個問題的。每一個客戶端既可以是接受數據的客戶端,又是上傳數據的服務端。用過 PPS和迅雷的童鞋就能很容易的理解了,這兩個軟件既要上傳數據,又要下載數據。看下面兩幅圖:

 

圖一:圍繞中心服務器打轉

 

圖二:P2P分布

實例的功能

我實現的這個例子的功能是:在一個局域網內,有很多台電腦。當其中一台電腦實現了復制或者剪貼,在其他的電腦上將顯示復制和剪貼的數據。你可以實現 Ctrl+C或者Ctrl+X進行數據復制或者剪貼。在其他的電腦上有一個窗體專門顯示你復制或者剪貼的數據(限定了文本數據)。

實現這個程序有兩個難點:

1、如何監聽Ctrl+C或者Ctrl+X等事件

2、不需要特定的服務端(不通過WCF的雙工通信),如果通過P2P去實現數據通信。

實例的實現:

下面根據這兩個難點來展開去實現。

一、事件監聽:

1、在WindowsForm應用程序中,protected override void WndProc(ref System.Windows.Forms.Message m)方法可以供我們去重載來實現事件的監聽。判斷Message的編號,如果是復制或者剪貼事件。我們就去通過WCF的P2P服務來廣播剪貼板中的信息。代碼如下:

protected override void WndProc(ref System.Windows.Forms.Message m)
         {
             // defined in winuser.h
             const int WM_DRAWCLIPBOARD = 0x308;
             const int WM_CHANGECBCHAIN = 0x030D;
             switch (m.Msg)
             {
                 case WM_DRAWCLIPBOARD:
                     DisplayClipboardData();
                     SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                     break;
                 case WM_CHANGECBCHAIN:
                     if (m.WParam == nextClipboardViewer)
                         nextClipboardViewer = m.LParam;
                     else
                         SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                     break;
                 default:
                     base.WndProc(ref m);
                     break;
             }
         }

2、然後提交給User32.dll處理:

[DllImport("User32.dll")]
         protected static extern int SetClipboardViewer(int hWndNewViewer);
         [DllImport("User32.dll", CharSet = CharSet.Auto)]
         public static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
         [DllImport("user32.dll", CharSet = CharSet.Auto)]
         public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

通過上面的代碼,我們解決了第一個問題:如何監聽Ctrl+C或者Ctrl+X等事件。

二、在WCF中,我們要通過NetPeerTcpBinding實現P2P。

下面我就一步一步的實現這個P2P的應用服務。

1、定義契約和實現契約:

[ServiceContract(CallbackContract = typeof(IShare))]
     public interface IShare
     {
        [OperationContract(IsOneWay = true)]
        void ShareClipboard(string type,string message);
     }
     public class ShareImplementation : IShare
     {
         private static Form m_receiverForm;
         private  static ClipEventHandler m_OnClipReceive;
         public void ShareClipboard(string type,string message)
         {
             try
             {
                 m_receiverForm.Invoke(m_OnClipReceive, type, message);
             }
             catch (Exception e)
             {
                 MessageBox.Show(e.ToString());
             }
         }
        public void SetForm(Form form,ClipEventHandler theCallback)
        {
            m_receiverForm = form;

            m_OnClipReceive = theCallback;
        }
     }

使用一個類來管理這個服務:

public class Peer
     {
         public string Id { get; private set; }
         public IShare Channel;
         public ShareImplementation Host;
         public ClipEventHandler clipeventhandler;
         public Form form;
         public Peer(string id)
         {
             Id = id;
         }

         private DuplexChannelFactory<IShare> _factory;
            public void StartService()
     {
         var binding = new NetPeerTcpBinding();
         binding.Security.Mode = SecurityMode.None;

         var endpoint = new ServiceEndpoint(
             ContractDescription.GetContract(typeof(IShare)),
             binding,
             new EndpointAddress("net.p2p://SimpleP2P"));
         Host = new ShareImplementation();
         Host.SetForm(form,clipeventhandler);
         _factory = new DuplexChannelFactory<IShare>(new InstanceContext(Host), endpoint);

         var channel = _factory.CreateChannel();

         ((ICommunicationObject)channel).Open();

         // wait until after the channel is open to allow access.
         Channel = channel;
     }
     public void StopService()
     {
         ((ICommunicationObject)Channel).Close();
         if (_factory != null)
             _factory.Close();
     }
     private readonly AutoResetEvent _stopFlag = new AutoResetEvent(false);
     public void Run()
     {
         Console.WriteLine("[ Starting Service ]");
         StartService();
         Console.WriteLine("[ Service Started ]");
         _stopFlag.WaitOne();
         Console.WriteLine("[ Stopping Service ]");
         StopService();
         Console.WriteLine("[ Service Stopped ]");
     }
     public void Stop()
     {
         _stopFlag.Set();
     }
     }

在WindowsForm中,通過DisplayClipboardData()方法來調用此服務,代碼如下。

void DisplayClipboardData()
         {
             try
             {
                 IDataObject iData = new DataObject();
                 string type = " ",message="";

                 iData = Clipboard.GetDataObject();
                 if (Clipboard.ContainsText())
                 {
                     message = (string)iData.GetData(DataFormats.Text);
                 }

                 if (peer != null && peer.Channel != null)
                 {
                     peer.Channel.ShareClipboard("text", message);
                 }
             }
             catch (Exception e)
             {
                 MessageBox.Show(e.ToString());
             }
         }

還有就是一個方法來接受信息方法AddToClip,代碼如下:

public void AddToClip(string type, string message)
         {
             if (type == "rtf")
             {
                 IDataObject iData = new DataObject(DataFormats.Rtf, message);
                 richTextBox1.Rtf = (string)iData.GetData(DataFormats.Rtf);
                 //richTextBox1.Rtf = message;
             }
             else if (type == "text")
                 richTextBox1.Text = message;
             else
                 richTextBox1.Text = "[Clipboard data is not RTF or ASCII Text]";
             richTextBox1.Text = message;
         }

由於WCF得回調和WindowsForm的主線程不是一個,故使用了一個委托:

public delegate void ClipEventHandler(string type ,string clipData);

其他詳細見代碼。

實例的效果:

在電腦zhuqilin上復制文本數據

在電腦Colin上顯示zhuqilin上復制的數據:

總結:

上星期用WCF的雙工實現了一個音頻聊天室的程序。有園友提出點對點的視頻、語音、聊天用P2P去實現效率和性能更好,故研究了一下WCF的P2P。本文就是一個簡單的WCF的P2P的例子。

擴展:

這篇文章只實現了文字剪貼板的共享功能。如果你有興趣,可以進一步擴展。

擴展1:數據直接傳遞到其他電腦的剪貼板上,可以直接Ctrl+V粘貼。

擴展2:現在只是實現文字剪貼板的共享。擴展成文件、視頻、圖片都可以。

效果可以是:如果局域網的兩個端點機器通過共享自己的剪貼板。在A機器上復制文件,在B機器上可以直接粘貼。

寫這個例子的靈感來自RealVNC。用過RealVNC的童鞋都知道,無論局域網還是外網,只要兩台pc建立連接,就能共享剪貼板上的數據了。

最後:建立P2P和打開P2P管道需要時間,故在運行這個程序的之後,需要等上一段時間才能共享你的剪貼板。如果有建議請留言,有幫助請推薦。thx。

出處:http://zhuqil.cnblogs.com

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved