您的位置:知识库 » .NET技术

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

作者: Leon Weng  来源: 博客园  发布时间: 2010-09-19 07:27  阅读: 1772 次  推荐: 0   原文链接   [收藏]  

  效果

  先看看效果再说,基本逻辑是两个人通过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

0
0
标签:Siverlight WCF

.NET技术热门文章

    .NET技术最新文章

      最新新闻

        热门新闻