稳扎稳打Silverlight(23) - 2.0通信之调用WCF的双向通信(Duplex Service)

[索引页]
[源码下载]


稳扎稳打Silverlight(23) - 2.0通信之调用WCF的双向通信(Duplex Service)


作者: webabcd


介绍
Silverlight 2.0 调用 WCF 的双向通信服务(Duplex Service) 。开发一个服务端主动向客服端发送股票信息的程序,首先客户端先向服务端发送需要监控的股票的股票代码,然后服务端在该股信息发生变化的时候将信息推送到客户端。
    服务端:
        定义服务契约及回调接口
        从当前上下文获取回调的客户端信道
        需要的话则向客户端信道“推”消息
    客户端:
        构造 PollingDuplexHttpBinding 并在其上创建 IDuplexSessionChannel 的信道工厂
        异步方式打开信道工厂
        异步方式打开信道
        构造需要发送到服务端的消息 System.ServiceModel.Channels.Message
        异步向服务端发送消息
        监听指定信道,用于异步方式接收服务端返回的消息
        不需要再接收服务端的消息则关闭信道


在线DEMO
http://www.cnblogs.com/webabcd/archive/2008/10/09/1307486.html


示例
服务端:
IDuplexService.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Runtime.Serialization;
using  System.ServiceModel;
using  System.Text;

using  System.ServiceModel.Channels;

/// <summary>
/// IDuplexService - 双工(Duplex)服务契约
/// CallbackContract - 双工(Duplex)服务的回调类型
/// </summary>

[ServiceContract(Namespace  =   " Silverlight20 " , CallbackContract  =   typeof (IDuplexClient))]
public   interface  IDuplexService
{
    
/// <summary>
    
/// 客户端向服务端发送消息的方法
    
/// </summary>
    
/// <param name="receivedMessage">客户端向服务端发送的消息 System.ServiceModel.Channels.Message</param>

    [OperationContract(IsOneWay = true)]
    
void SendStockCode(Message receivedMessage);
}


/// <summary>
/// 双工(Duplex)服务的回调接口
/// </summary>

public   interface  IDuplexClient
{
    
/// <summary>
    
/// 客户端接收服务端发送过来的消息的方法
    
/// </summary>
    
/// <param name="returnMessage">服务端向客户端发送的消息 System.ServiceModel.Channels.Message</param>

    [OperationContract(IsOneWay = true)]
    
void ReceiveStockMessage(Message returnMessage);
}


DuplexService.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Runtime.Serialization;
using  System.ServiceModel;
using  System.Text;

using  System.ServiceModel.Channels;
using  System.Threading;
using  System.ServiceModel.Activation;
using  System.IO;

/// <summary>
/// Duplex 服务的服务端的实现
/// 本文以客户端向服务端提交股票代码,服务端定时向客户端发送股票信息为例
/// </summary>

public   class  DuplexService : IDuplexService
{
    IDuplexClient _client;
    
bool _status = true;

    
/// <summary>
    
/// 客户端向服务端发送股票代码的方法
    
/// </summary>
    
/// <param name="receivedMessage">包含股票代码的 System.ServiceModel.Channels.Message </param>

    public void SendStockCode(Message receivedMessage)
    
{
        
// 获取当前上下文的回调信道
        _client = OperationContext.Current.GetCallbackChannel<IDuplexClient>();

        
// 如果发生错误则不再执行
        OperationContext.Current.Channel.Faulted += new EventHandler(delegate { _status = false; });

        
// 获取用户提交的股票代码
        string stockCode = receivedMessage.GetBody<string>();

        
// 每3秒向客户端发送一次股票信息
        while (_status)
        
{
            
// 构造需要发送到客户端的 System.ServiceModel.Channels.Message
            
// Duplex 服务仅支持 Soap11 , Action 为请求的目的地(需要执行的某行为的路径)
            Message stockMessage = Message.CreateMessage(
                MessageVersion.Soap11,
                
"Silverlight20/IDuplexService/ReceiveStockMessage",
                
string.Format("StockCode: {0}; StockPrice: {1}; CurrentTime: {2}",
                    stockCode,
                    
new Random().Next(1200),
                    DateTime.Now.ToString()));

            
try
            
{
                
// 向客户端“推”数据
                _client.ReceiveStockMessage(stockMessage);
            }

            
catch (Exception ex)
            
{
                
// 出错则记日志
                using (StreamWriter sw = new StreamWriter(@"C:/Silverlight_Duplex_Log.txt"true))
                
{
                    sw.Write(ex.ToString());
                    sw.WriteLine();
                }

            }


            System.Threading.Thread.Sleep(
3000);
        }

    }

}

PollingDuplexServiceHostFactory.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Web;

using  System.ServiceModel;
using  System.ServiceModel.Channels;
using  System.ServiceModel.Activation;

/* 以下部分摘自文档 */

//  服务 svc 文件的 Factory 要指定为此类
public   class  PollingDuplexServiceHostFactory : ServiceHostFactoryBase
{
    
public override ServiceHostBase CreateServiceHost(string constructorString,
        Uri[] baseAddresses)
    
{
        
return new PollingDuplexSimplexServiceHost(baseAddresses);
    }

}


class  PollingDuplexSimplexServiceHost : ServiceHost
{
    
public PollingDuplexSimplexServiceHost(params System.Uri[] addresses)
    
{
        
base.InitializeDescription(typeof(DuplexService), new UriSchemeKeyedCollection(addresses));
    }


    
protected override void InitializeRuntime()
    
{
        
// 配置 WCF 服务与 Silverlight 客户端之间的 Duplex 通信
        
// Silverlight 客户端定期轮询网络层上的服务,并检查回调信道上由服务端发送的所有新的消息
        
// 该服务会将回调信道上的由服务端发送的所有消息进行排队,并在客户端轮询服务时将这些消息传递到该客户端

        PollingDuplexBindingElement pdbe 
= new PollingDuplexBindingElement()
        
{
            
// ServerPollTimeout - 轮询超时时间
            
// InactivityTimeout - 服务端与客户端在此超时时间内无任何消息交换的情况下,服务会关闭其会话

            ServerPollTimeout 
= TimeSpan.FromSeconds(3),
            InactivityTimeout 
= TimeSpan.FromMinutes(1)
        }
;

        
// 为服务契约(service contract)添加一个终结点(endpoint)
        
// Duplex 服务仅支持 Soap11
        this.AddServiceEndpoint(
            
typeof(IDuplexService),
            
new CustomBinding(
                pdbe,
                
new TextMessageEncodingBindingElement(
                    MessageVersion.Soap11,
                    System.Text.Encoding.UTF8),
                
new HttpTransportBindingElement()),
                
"");

        
base.InitializeRuntime();
    }

}


DuplexService.svc
<% @ ServiceHost Language="C#" Debug="true" Service="DuplexService" CodeBehind="~/App_Code/DuplexService.cs" Factory="PollingDuplexServiceHostFactory"  %>


客户端:
DuplexService.xaml
< UserControl  x:Class ="Silverlight20.Communication.DuplexService"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml" >
    
< StackPanel  HorizontalAlignment ="Left"  Margin ="5" >
    
        
< TextBox  x:Name ="txtStockCode"  Text ="请输入股票代码"  Margin ="5"   />
        
< Button  x:Name ="btnSubmit"  Content ="获取股票信息"  Click ="btnSubmit_Click"  Margin ="5"   />
        
< Button  x:Name ="btnStop"  Content ="停止获取"  Click ="btnStop_Click"   Margin ="5"   />
        
< TextBlock  x:Name ="lblStockMessage"  Margin ="5"   />
    
    
</ StackPanel >
</ UserControl >

DuplexService.xaml.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Net;
using  System.Windows;
using  System.Windows.Controls;
using  System.Windows.Documents;
using  System.Windows.Input;
using  System.Windows.Media;
using  System.Windows.Media.Animation;
using  System.Windows.Shapes;

using  System.ServiceModel;
using  System.ServiceModel.Channels;
using  System.Threading;
using  System.IO;

namespace  Silverlight20.Communication
{
    
public partial class DuplexService : UserControl
    
{
        SynchronizationContext _syncContext;

        
// 是否接收服务端发送过来的消息
        bool _status = true;

        
public DuplexService()
        
{
            InitializeComponent();
        }


        
private void btnSubmit_Click(object sender, RoutedEventArgs e)
        
{
            _status 
= true;

            
// UI 线程
            _syncContext = SynchronizationContext.Current;

            PollingDuplexHttpBinding binding 
= new PollingDuplexHttpBinding()
            
{
                
// InactivityTimeout - 服务端与客户端在此超时时间内无任何消息交换的情况下,服务会关闭其会话
                InactivityTimeout = TimeSpan.FromMinutes(1)
            }
;

            
// 构造 IDuplexSessionChannel 的信道工厂
            IChannelFactory<IDuplexSessionChannel> factory =
                binding.BuildChannelFactory
<IDuplexSessionChannel>(new BindingParameterCollection());

            
// 打开信道工厂
            IAsyncResult factoryOpenResult =
                factory.BeginOpen(
new AsyncCallback(OnOpenCompleteFactory), factory);

            
if (factoryOpenResult.CompletedSynchronously)
            
{
                
// 如果信道工厂被打开的这个 异步操作 已经被 同步完成 则执行下一步
                CompleteOpenFactory(factoryOpenResult);
            }

        }


        
private void btnStop_Click(object sender, RoutedEventArgs e)
        
{
            _status 
= false;
        }


        
void OnOpenCompleteFactory(IAsyncResult result)
        
{
            
// 该异步操作已被同步完成的话则不做任何操作,反之则执行下一步
            if (result.CompletedSynchronously)
                
return;
            
else
                CompleteOpenFactory(result);
        }


        
void CompleteOpenFactory(IAsyncResult result)
        
{
            IChannelFactory
<IDuplexSessionChannel> factory = result.AsyncState as IChannelFactory<IDuplexSessionChannel>;

            
// 完成异步操作,以打开信道工厂
            factory.EndOpen(result);

            
// 在信道工厂上根据指定的地址创建信道
            IDuplexSessionChannel channel =
                factory.CreateChannel(
new EndpointAddress("http://localhost:3036/DuplexService.svc"));

            
// 打开信道
            IAsyncResult channelOpenResult =
                channel.BeginOpen(
new AsyncCallback(OnOpenCompleteChannel), channel);

            
if (channelOpenResult.CompletedSynchronously)
            
{
                
// 如果信道被打开的这个 异步操作 已经被 同步完成 则执行下一步
                CompleteOpenChannel(channelOpenResult);
            }

        }


        
void OnOpenCompleteChannel(IAsyncResult result)
        
{
            
// 该异步操作已被同步完成的话则不做任何操作,反之则执行下一步
            if (result.CompletedSynchronously)
                
return;
            
else
                CompleteOpenChannel(result);
        }


        
void CompleteOpenChannel(IAsyncResult result)
        
{
            IDuplexSessionChannel channel 
= result.AsyncState as IDuplexSessionChannel;

            
// 完成异步操作,以打开信道
            channel.EndOpen(result);

            
// 构造需要发送到服务端的 System.ServiceModel.Channels.Message (客户端终结点与服务端终结点之间的通信单元)
            Message message = Message.CreateMessage(
                channel.GetProperty
<MessageVersion>(), // MessageVersion.Soap11 (Duplex 服务仅支持 Soap11)
                "Silverlight20/IDuplexService/SendStockCode"// Action 为请求的目的地(需要执行的某行为的路径)
                txtStockCode.Text);

            
// 向目的地发送消息
            IAsyncResult resultChannel =
                channel.BeginSend(message, 
new AsyncCallback(OnSend), channel);

            
if (resultChannel.CompletedSynchronously)
            
{
                
// 如果向目的地发送消息的这个 异步操作 已经被 同步完成 则执行下一步
                CompleteOnSend(resultChannel);
            }


            
// 监听指定的信道,用于接收返回的消息
            ReceiveLoop(channel);
        }


        
void OnSend(IAsyncResult result)
        
{
            
// 该异步操作已被同步完成的话则不做任何操作,反之则执行下一步
            if (result.CompletedSynchronously)
                
return;
            
else
                CompleteOnSend(result);
        }


        
void CompleteOnSend(IAsyncResult result)
        
{
            
try
            
{
                IDuplexSessionChannel channel 
= (IDuplexSessionChannel)result.AsyncState;

                
// 完成异步操作,以完成向目的地发送消息的操作
                channel.EndSend(result);
            }

            
catch (Exception ex)
            
{
                _syncContext.Post(WriteText, ex.ToString() 
+ Environment.NewLine);
            }

        }


        
void ReceiveLoop(IDuplexSessionChannel channel)
        
{
            
// 监听指定的信道,用于接收返回的消息
            IAsyncResult result = 
                channel.BeginReceive(
new AsyncCallback(OnReceiveComplete), channel);

            
if (result.CompletedSynchronously)
            
{
                CompleteReceive(result);
            }

        }


        
void OnReceiveComplete(IAsyncResult result)
        
{
            
if (result.CompletedSynchronously)
                
return;
            
else
                CompleteReceive(result);
        }


        
void CompleteReceive(IAsyncResult result)
        
{
            IDuplexSessionChannel channel 
= (IDuplexSessionChannel)result.AsyncState;

            
try
            
{
                
// 完成异步操作,以接收到服务端发过来的消息
                Message receivedMessage = channel.EndReceive(result);

                
if (receivedMessage == null)
                
{
                    
// 服务端会话已被关闭
                    
// 此时应该关闭客户端会话,或向服务端发送消息以启动一个新的会话
                }

                
else
                
{
                    
// 将接收到的信息输出到界面上
                    string text = receivedMessage.GetBody<string>();
                    _syncContext.Post(WriteText, text 
+ Environment.NewLine);

                    
if (!_status)
                    
{
                        
// 关闭信道
                        IAsyncResult resultFactory =
                            channel.BeginClose(
new AsyncCallback(OnCloseChannel), channel);

                        
if (resultFactory.CompletedSynchronously)
                        
{
                            CompleteCloseChannel(result);
                        }


                    }

                    
else
                    
{
                        
// 继续监听指定的信道,用于接收返回的消息
                        ReceiveLoop(channel);
                    }

                }

            }

            
catch (Exception ex)
            
{
                
// 出错则记日志
                using (StreamWriter sw = new StreamWriter(@"C:/Silverlight_Duplex_Log.txt"true))
                
{
                    sw.Write(ex.ToString());
                    sw.WriteLine();
                }

            }

        }


        
void OnCloseChannel(IAsyncResult result)
        
{
            
if (result.CompletedSynchronously)
                
return;
            
else
                CompleteCloseChannel(result);
        }


        
void CompleteCloseChannel(IAsyncResult result)
        
{
            IDuplexSessionChannel channel 
= (IDuplexSessionChannel)result.AsyncState;

            
// 完成异步操作,以关闭信道
            channel.EndClose(result);
        }


        
void WriteText(object text)
        
{
            
// 将信息打到界面上
            lblStockMessage.Text += (string)text;
        }

    }

}


OK
[源码下载]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值