Siverlight与WCF通信之双工netTcp实现视频对话

效果

先看看效果再说,基本逻辑是两个人通过Silverlight端,借助TCP协议分别向服务器不断传输视频,服务器接收到视频后,会检测这些视频是发给谁的,然后回调某个客户端来接收并显示这些视频。

image

实现

双工的服务契约定义

    [ServiceContract(CallbackContract=typeof(IChatServiceCallBack))]

    public interface IChatService

    { 

        [OperationContract]

        void SendVideo(UserVideo userVideo);

    }

    [ServiceContract]

    public interface IChatServiceCallBack

    {

        [OperationContract(IsOneWay=true)]

        void GetVideos(List<UserVideo> listVideos);

    }

数据契约,由三部分组成,发送者,接受者和视频流,方便服务器进行判断,选择接收的回调句柄。
    [DataContract]

    public class UserVideo

    {

        [DataMember]

        public string UserName { get; set; }

        [DataMember]

        public string PartnerName { set; get; }

        [DataMember]

        public byte[] VideoByte { set; get; }

    } 

既然是双工的,当然我们还需要定义一个客户端的回调句柄类,包括两个属性,一个是客户端名称,一个是回调句柄
public class ClientHandler {
 public string Name { set; get; } 
 public IChatServiceCallBack Client { set; get; } } 
服务实现,这里没有采用定时检测视频集合,而是在每次有客户端上传视频时进行检测并回调客户端来接收,这样做的好处是事件驱动,比定时检测更具有准确性
public class ChatService : IChatService

    {

        static List<ClientHandler> listOfClientHandler = new List<ClientHandler>();

        private static List<UserVideo> listVideos = new List<UserVideo>();

        IChatServiceCallBack client;

        public void SendVideo(UserVideo userVideo)

        {

            Console.WriteLine("receiving...");

            listVideos.Add(userVideo);

            

            client = OperationContext.Current.GetCallbackChannel<IChatServiceCallBack>();

            if (listOfClientHandler.Where(m => m.Name == userVideo.UserName).Count() == 0)

            {

                listOfClientHandler.Add(new ClientHandler() { Name=userVideo.UserName, Client=client });

            }



            foreach(var item in listOfClientHandler)

            {

                if (listVideos.Where(m => m.PartnerName == item.Name).Count() > 0)

                {

                    var videos = listVideos.Where(m => m.PartnerName == item.Name).ToList();

                    item.Client.GetVideos(videos);

                    Console.WriteLine("sending...");

                    listVideos.RemoveAll(m => m.PartnerName == item.Name);//处理一个视频后直接从服务器上删除此视频

                }

            }

        }

    }
客户端,基本原理是先发送视频,然后定义回调函数来处理服务器的回调:
void btnSendVideo_Click(object sender, RoutedEventArgs e)

        {

            System.Windows.Threading.DispatcherTimer timer = new System.Windows.Threading.DispatcherTimer();

            timer.Interval = new TimeSpan(0, 0, 0, 0, 200);

            timer.Tick += new EventHandler(timer_Tick);

            timer.Start(); 

        } 



        void timer_Tick(object sender, EventArgs e)

        {

            proxy = new ChatServiceClient();

            proxy.GetVideosReceived += new EventHandler<GetVideosReceivedEventArgs>(proxy_GetVideosReceived);

            WriteableBitmap bmp = new WriteableBitmap(this.rectangleUser, null);

            MemoryStream ms = new MemoryStream();

            EncodeJpeg(bmp, ms);

            UserVideo userVideo = new UserVideo();

            userVideo.PartnerName = this.Partner;

            userVideo.UserName = this.User;

            userVideo.VideoByte = ms.GetBuffer();

            proxy.SendVideoCompleted += (se,ev) => { };

            proxy.SendVideoAsync(userVideo);

        }



        void proxy_GetVideosReceived(object sender, GetVideosReceivedEventArgs e)

        {

            foreach (ChatService.UserVideo video in e.listVideos)

            {

                MemoryStream ms = new MemoryStream(video.VideoByte);

                BitmapImage bitmap = new BitmapImage();

                bitmap.SetSource(ms);

                imagePartner.Source = bitmap;

                ms.Close();

            }

        }
app.config配置 
<system.serviceModel>

    <bindings>

      <netTcpBinding>

        <binding name="netTcpBindConfig"

                 closeTimeout="00:01:00"

                 openTimeout="00:01:00"

                 receiveTimeout="00:10:00"

                 sendTimeout="00:01:00"

                 transactionFlow="false"

                 transferMode="Buffered"

                 transactionProtocol="OleTransactions"

                 hostNameComparisonMode="StrongWildcard"

                 listenBacklog="10"

                 maxBufferPoolSize="2147483647 "

                 maxBufferSize="2147483647 "

                 maxConnections="10"

                 maxReceivedMessageSize="2147483647 ">

          <readerQuotas maxDepth="32"

                        maxStringContentLength="2147483647 "

                        maxArrayLength="2147483647 "

                        maxBytesPerRead="4096"

                        maxNameTableCharCount="16384" />

          <reliableSession ordered="true"

                           inactivityTimeout="00:10:00"

                           enabled="false" />

          <security mode="None"> 

          </security>

        </binding>        

      </netTcpBinding>

    </bindings>

    <services>



      <service behaviorConfiguration="Server.ChatServiceBehavior" name="Server.ChatService">

        <host>

          <baseAddresses>

            <add baseAddress="net.tcp://localhost:4503/ChatService"/>

          </baseAddresses>

        </host>

        <endpoint address="" binding="netTcpBinding" contract="Server.IChatService" bindingConfiguration="netTcpBindConfig"></endpoint>

        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" ></endpoint>

      </service>



    </services>

    <behaviors>

      <serviceBehaviors>

        <behavior name="Server.ChatServiceBehavior">

          <serviceMetadata/>

          <serviceDebug includeExceptionDetailInFaults="false"/>

        </behavior>

      </serviceBehaviors>

    </behaviors>

  </system.serviceModel>

遗留问题

1,由于客户端是定时上传视频流,而非长连接方式,需要不停的调用服务器来上传视频,有些耗资源,并且有时会出现下面的异常,猜想是由于不停的连接导致。

image

 

 

 

 

2,wcf传输方式配置的是transferMode="Buffered",这种方式并不适合流式传输。实时性上仍有待改进。

 

http://files.cnblogs.com/wengyuli/chatTCPduplex.rar


你可能感兴趣的:(WCF)