使用WCF和F#进程之间的通信进程、通信、WCF

2023-09-06 13:12:22 作者:是夜在熬我

我想作一个简单的一对一通信的两个很长一段时间的运行使用F#F#的过程。他们会定期交换信息的每个约5秒。到现在为止,我已经达到了这一点:

  r组成System.ServiceModel
r组成System.Runtime.Serialization
//# -  [R @D:\ DLL \ protobuf的\ protobuf的,net.dll
#TIME上

开System.ServiceModel

并[d的ServiceContract&GT]
键入IService =
  并[d OperationContract的&GT]
  //并[d ProtoBuf.ServiceModel.ProtoBehavior&GT]
  抽象测试:浮法[] [] []  - >串

类型服务()=
  与接口IService
    会员o.Test数据= sprintf的你好,%数据

让服务器= System.Threading.Thread(乐趣() -  GT;
  让SVH =新的ServiceHost(typeof运算<服务>)
  svh.AddServiceEndpoint(typeof运算&其中; IService>中NetNamedPipeBinding(),net.pipe://本地主机/ 123)|>忽略
  svh.Open())

server.IsBackground<  - 真
server.Start()

让SCF:IService = ChannelFactory.CreateChannel(NetNamedPipeBinding()的EndpointAddressnet.pipe://本地主机/ 123)
让RND = System.Random()
让ARR =
  Array.init 100(我的乐趣 - >
    Array.init 10(有趣的J  - >
      Array.init 10(有趣的k  - >
        rnd.NextDouble()
  )))

printfn%S(scf.Test ARR)
 

我收到了很多不同的异常,主要是由于不同的WCF安全限制。

我的问题是

在做什么,我需要做的最小,使其工作? 难道我写的code正确,使通信尽可能快? 我曾尝试包括protobuf的串行器(见ProtoBehavior在code),使序列化更快。难道我正确实施它?我怎么知道,WCF实际使用与否? 解决方案

您需要增加 MaxReceivedMessageSize 的上的结合从它的65536在客户端和服务器上的默认值,以容纳数据的要传输的音量。属性

操作系统 二 2.进程控制和进程通信

您可以使用消息检查来检查,如果WCF实际上是使用protobuf的串行器(它是不是)。所述ProtoBehavior似乎只适用于值与指定的DataContract / ProtoContract属性。因此,在修改下面的例子中我已经创建了一个矢量记录类型,还标有F#3的 CLIMutable 属性,来包装数组:

  r组成System.ServiceModel
r组成System.Runtime.Serialization
r组成的protobuf-net.dll
#TIME上

开System.ServiceModel
开System.Runtime.Serialization

并[d DataContract; ProtoBuf.ProtoContract; CLIMutable>]
型矢量<T> = {并[d数据成员; ProtoBuf.ProtoMember(1)>]值:'T []}

并[d的ServiceContract&GT]
键入IService =
  并[d OperationContract的&GT]
  并[d ProtoBuf.ServiceModel.ProtoBehavior&GT]
  抽象测试:矢量<矢量<矢量<浮动>>> - >串

类型服务()=
  与接口IService
    会员o.Test数据= sprintf的你好,%数据

让服务器= System.Threading.Thread(乐趣() -  GT;
  让SVH =新的ServiceHost(typeof运算<服务>)
  让我们结合= NetNamedPipeBinding()
  binding.MaxReceivedMessageSize<  -  binding.MaxReceivedMessageSize * 4L
  svh.AddServiceEndpoint(typeof运算< IService>中结合,net.pipe://本地主机/ 123)|>忽略
  svh.Open())

server.IsBackground<  - 真
server.Start()

让SCF:IService =
   让我们结合= NetNamedPipeBinding()
   binding.MaxReceivedMessageSize<  -  binding.MaxReceivedMessageSize * 4L
   ChannelFactory.CreateChannel(绑定的EndpointAddressnet.pipe://本地主机/ 123)
让RND = System.Random()
让ARR =
  {值= Array.init 100(我的乐趣 - >
   {值=
      Array.init 10(有趣的J  - >
         {值= Array.init 10(有趣的k  - > rnd.NextDouble())}
      )}
   )}

printfn%S(scf.Test ARR)
 

I would like to make a simple one to one communication between two long time running F# processes using F#. They will exchange information regularly every ca. 5 seconds. Until now, I have reached this point:

#r "System.ServiceModel"
#r "System.Runtime.Serialization"
//#r @"d:\DLL\Protobuf\protobuf-net.dll"
#time "on"

open System.ServiceModel

[<ServiceContract>]
type IService =
  [<OperationContract>]
  // [<ProtoBuf.ServiceModel.ProtoBehavior>]
  abstract Test: float [] [] [] -> string

type Service () =
  interface IService with
    member o.Test data = sprintf "Hello, %A" data

let server = System.Threading.Thread (fun () ->
  let svh = new ServiceHost (typeof<Service>)
  svh.AddServiceEndpoint (typeof<IService>, NetNamedPipeBinding(), "net.pipe://localhost/123") |> ignore
  svh.Open () )

server.IsBackground <- true
server.Start()

let scf: IService = ChannelFactory.CreateChannel (NetNamedPipeBinding(), EndpointAddress "net.pipe://localhost/123")
let rnd = System.Random ()
let arr =
  Array.init 100 (fun i ->
    Array.init 10 (fun j ->
      Array.init 10 (fun k ->
        rnd.NextDouble()
  )))

printfn "%s" (scf.Test arr)

I get a plenty of different exceptions mainly due to different WCF security limits.

My questions are

What do I need to do at minimum to make it work? Did I write the code correctly to make the communication as fast as possible? I have tried to include ProtoBuf serializer (see ProtoBehavior in the code) to make the serialization even faster. Did I implemented it correctly? How do I know that WCF actually uses it or not?

解决方案

You need to increase MaxReceivedMessageSize property on the binding from it's default value of 65536 on both the client and server to accommodate the volume of data you are transferring.

You can use a Message Inspector to check if WCF is actually using the ProtoBuf serializer (which it isn't). The ProtoBehavior appears to only be applied to values with a DataContract/ProtoContract attribute specified. So in the modified example below I have created a Vector record type, also marked with the F# 3 CLIMutable attribute, to wrap the arrays:

#r "System.ServiceModel"
#r "System.Runtime.Serialization"
#r "protobuf-net.dll"
#time "on"

open System.ServiceModel
open System.Runtime.Serialization

[<DataContract; ProtoBuf.ProtoContract; CLIMutable>]
type Vector<'T> = { [<DataMember; ProtoBuf.ProtoMember(1)>] Values : 'T[] }

[<ServiceContract>]
type IService =
  [<OperationContract>]
  [<ProtoBuf.ServiceModel.ProtoBehavior>]
  abstract Test: Vector<Vector<Vector<float>>> -> string

type Service () =
  interface IService with
    member o.Test data = sprintf "Hello, %A" data

let server = System.Threading.Thread (fun () ->
  let svh = new ServiceHost (typeof<Service>)
  let binding = NetNamedPipeBinding()
  binding.MaxReceivedMessageSize <- binding.MaxReceivedMessageSize * 4L
  svh.AddServiceEndpoint (typeof<IService>, binding, "net.pipe://localhost/123") |> ignore
  svh.Open () )

server.IsBackground <- true
server.Start()

let scf: IService = 
   let binding = NetNamedPipeBinding()
   binding.MaxReceivedMessageSize <- binding.MaxReceivedMessageSize * 4L
   ChannelFactory.CreateChannel (binding, EndpointAddress "net.pipe://localhost/123")
let rnd = System.Random ()
let arr =
  { Values = Array.init 100 (fun i ->
   { Values =
      Array.init 10 (fun j ->
         { Values =Array.init 10 (fun k -> rnd.NextDouble()) }
      )}
   )}

printfn "%s" (scf.Test arr)