WCF:消息框架和自定义渠道

时间:2009-12-07 18:58:34

标签: wcf wcf-extensions

我试图了解如何使用WCF实现消息框架。目标是在WCF中创建一个可以通过Tcp处理专有格式的服务器。我不能使用net.Tcp绑定,因为那只适用于SOAP。

我需要编写一个自定义频道,以下列格式接收消息 。示例消息将是“5 abcde”。特别是我不知道如何在我的自定义渠道中进行框架。

以下是一些示例代码

class CustomChannel: IDuplexSessionChannel
{
private class PendingRead
{
    public NetworkStream Stream = null;
    public byte[] Buffer = null;
    public bool IsReading = false;
}

private CommunicationState state = CommunicationState.Closed;
private TcpClient tcpClient = null;
private MessageEncoder encoder = null;
private BufferManager bufferManager = null;
private TransportBindingElement bindingElement = null;
private Uri uri = null;
private PendingRead pendingRead;

public CustomChannel(Uri uri, TransportBindingElement bindingElement, MessageEncoderFactory encoderFactory, BufferManager bufferManager, TcpClient tcpClient)
{
    this.uri = uri;
    this.bindingElement = bindingElement;
    this.tcpClient = tcpClient;
    this.bufferManager = bufferManager;     
    state = CommunicationState.Created;
  }

public IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state)
{
    if (this.state != CommunicationState.Opened) return null;

    byte[] buffer = bufferManager.TakeBuffer(tcpClient.Available);
    NetworkStream stream = tcpClient.GetStream();
    pendingRead = new PendingRead { Stream = stream, Buffer = buffer, IsReading = true };
    IAsyncResult result = stream.BeginRead(buffer, 0, buffer.Length, callback, state);
    return result;
}
public bool EndTryReceive(IAsyncResult result, out Message message)
{
    int byteCount =  tcpClient.Client.EndReceive(result);
    string content = Encoding.ASCII.GetString(pendingRead.buffer)

     // framing logic here

     Message.CreateMessage( ... )
}   

}

所以基本上第一次围绕EndTryReceive可以从挂起的读缓冲区“5 ab”中获取一条消息。然后第二次围绕它可以得到剩下的消息。问题是当第一次调用EndTryReceive时,我被迫创建一个Message对象,这意味着将有一个部分Message上传到通道堆栈。

我真正想做的是确保我在缓冲区中有完整的消息“5 abcde”,这样当我在EndTryReceive中构造消息时,它就是一个完整的消息。

有没有人有任何关于他们如何使用WCF进行自定义框架的示例?

谢谢, 瓦迪姆

2 个答案:

答案 0 :(得分:3)

线路级别的帧不是WCF信道模型真正关心的;它几乎取决于你处理它。

我的意思是,您有责任确保您的传输渠道在接收上返回“整个”消息(流式传输稍有变化,但最多只能变化到某一点)。

在您的情况下,您似乎正在将通道上的接收操作直接转换为底层套接字上的接收操作,而这是不可行的,因为这不会让您有机会强制执行您自己的框架规则

实际上,你的频道上的单个接收操作可能很好地转换为底层套接字上的多个接收操作,这很好(你仍然可以做所有异步,所以它不需要影响那个一部分)。

基本上问题就变成了:你的协议框架模型是什么样的?在这里疯狂猜测,但它看起来像消息是长度前缀,长度编码为十进制字符串? (看起来很烦人)。

我认为在这种情况下你最好的选择是让你的传输缓冲区传入数据(比如说,最多64KB的数据或其他),然后在每次接收操作时检查缓冲区以查看它是否包含足够的字节来提取传入消息的长度。如果是这样,那么要么从缓冲区中读取所需的字节数,要么刷新缓冲区并从套接字读取尽可能多的字节。你必须要小心,因为根据你的协议的工作方式,我假设你可能会在你真正需要之前阅读部分消息。

答案 1 :(得分:0)

我同意托马斯的观点。您可以在Microsoft技术示例“ChunkingChannel”中找到一些基本灵感。