【发布时间】:2010-10-05 19:00:23
【问题描述】:
我正在编写一个 WCF (net.tcp) 文件传输服务,该服务最终会将文件拆分为多个部分,并将这些部分从服务器/服务传输到客户端。目前客户端和服务器是控制台应用程序。
在编写此服务时,我多次遇到以下异常;
System.ServiceModel.CommunicationException:套接字连接已中止。这可能是由于处理您的消息时出错或远程主机超出接收超时,或者是潜在的网络资源问题引起的。本地套接字超时为“01:59:59.4220000”。
其实一开始是Unhandled Exception: System.Reflection.TargetInvocationException: 操作过程中发生异常,导致结果无效。检查 InnerException 以获取异常详细信息。 ---> 那么上面的 CommunicationException 文本就在这里。
按照典型的 Microsoft 方式,该异常消息毫无帮助,因此我终于向社区呼吁,看看我是否可以解决这个问题。
此外,如果这很重要,客户端将异步调用服务的两个方法( InitGetFilePart() 和 GetFilePart() )。根据我的日志,对 InitGetFilePartAsync(1, 1) 的第一次调用会一直处理到最后;这意味着它的“已完成”处理程序被调用,该处理程序又调用 vcClient.GetFilePartAsync(FileXferCargo, 1),然后它的处理程序产生一个 BackgroundWorker 线程 (workers[chunkNum]. RunWorkerAsync(cargoHolder[chunkNum] where chunkNum=1) 本身完成。这是我得到上述 TargetInvocationException 的时间。
过去我对 App.config 进行了各种调整(遗憾的是,我不记得具体是什么)以消除此异常,但现在我所做的任何事情似乎都没有任何区别,我只是不明白为什么会一直这样。
我已阅读有关此问题的其他建议,包括“您必须在客户端捕获异常,中止当前代理并创建并打开新代理。”好吧,我试过了,但我似乎无法捕捉到这个异常。
我还读到这可能是由于通过网络发送了太多数据,但是当我尝试发送我的小 4k 测试文件时,我得到了同样的异常。在我的调查中,我还读到我可以调用 1 个 WCF 服务函数/方法,多次使用带有 UserState 参数的 *Async() 调用,我正在这样做。
我承认在 WCF 方面我是一个相对的 n00b,但我很确定我的配置文件设置正确,适合我正在尝试做的事情。
这里是客户端和服务器 app.config 文件、服务接口定义和服务实现类的顶部。
客户端的 App.config:
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="MyTcpBinding_IFileXferService"
receiveTimeout="02:00:00"
sendTimeout="02:00:00"
transferMode="Streamed"
maxBufferSize="65536"
maxReceivedMessageSize="2147483647">
<readerQuotas maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="65536" />
<security mode="Transport">
<transport clientCredentialType="None">
<extendedProtectionPolicy policyEnforcement="Never" />
</transport>
</security>
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="ClientConfigBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="None" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint name="ClientConfig"
behaviorConfiguration="ClientConfigBehavior"
binding="netTcpBinding"
bindingConfiguration="MyTcpBinding_IFileXferService"
contract="ServiceRefs.IFileXferService" />
</client>
</system.serviceModel>
服务器的 App.config:
<bindings>
<netTcpBinding>
<!-- Under <netTcpBinding> setting the listenBacklog,
maxConnections, and maxBuffer* values high -->
<binding name="MyTcpBinding_IFileXferService"
receiveTimeout="02:00:00"
sendTimeout="02:00:00"
openTimeout="00:01:00"
transferMode="Streamed"
portSharingEnabled="true"
listenBacklog="32"
maxConnections="64"
maxBufferSize="65536"
maxReceivedMessageSize="2147483646">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="MediaServer.LNMediaServerSvc"
behaviorConfiguration="ServerConfigBehavior">
<host>
<baseAddresses>
<add baseAddress="net.tcp://lngsead148191a:9000/fileXferSvc"/>
</baseAddresses>
</host>
<endpoint name="mainEndPoint"
binding="netTcpBinding"
bindingConfiguration="MyTcpBinding_IFileXferService"
contract="ServiceInterfaces.IFileXferService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServerConfigBehavior">
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceThrottling maxConcurrentCalls="64" />
<dataContractSerializer maxItemsInObjectGraph="2147483646" />
<serviceCredentials>
<serviceCertificate findValue="tp_value"
x509FindType="FindByThumbprint" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Service接口定义如下;
[DataContract(IsReference = true)]
public class FileData
{
private long m_startPos;
[DataMember]
public long StartPosition
{
get { return m_startPos; }
set { m_startPos = value; }
}
private long m_endPos;
[DataMember]
public long EndPosition
{
get { return m_endPos; }
set { m_endPos = value; }
}
private byte m_chunkNumber;
[DataMember]
public byte ChunkNumber
{
get { return m_chunkNumber; }
set { m_chunkNumber = value; }
}
private long m_chunkSize;
[DataMember]
public long ChunkSize
{
get { return m_chunkSize; }
set { m_chunkSize = value; }
}
private string md5Hash;
[DataMember]
public string MD5Hash
{
get { return md5Hash; }
set { md5Hash = value; }
}
private string m_destFileSpec;
[DataMember]
public string DestinationFileSpec
{
get { return m_destFileSpec; }
set { m_destFileSpec = value; }
}
private string m_srcFileSpec;
[DataMember]
public string SourceFileSpec
{
get { return m_srcFileSpec; }
set { m_srcFileSpec = value; }
}
private Stream m_sourceStream;
[DataMember]
public Stream SourceStream
{
get { return m_sourceStream; }
set { m_sourceStream = value; }
}
private UInt32 m_JobNo;
[DataMember]
public UInt32 JobNumber
{
get { return m_JobNo; }
set { m_JobNo = value; }
}
private UInt32 m_fileNumber;
[DataMember]
public UInt32 FileNumber
{
get { return m_fileNumber; }
set { m_fileNumber = value; }
}
private long m_fileSize;
[DataMember]
public long FileSize
{
get { return m_fileSize; }
set { m_fileSize = value; }
}
}
[DataContract]
public partial class FileXferCargo
{
private FileData m_fileData;
[DataMember]
public FileData FileData
{
get { return m_fileData; }
set { m_fileData = value; }
}
private bool m_cancelled;
[DataMember]
public bool Cancelled
{
get { return m_cancelled; }
set { m_cancelled = value; }
}
private long m_errorCode;
[DataMember]
public long ErrorCode
{
get { return m_errorCode; }
set { m_errorCode = value; }
}
private Exception m_exceptionObj;
[DataMember]
public Exception Exception
{
get { return m_exceptionObj; }
set { m_exceptionObj = value; }
}
}
[ServiceContract]
public interface IFileXferService
{
[OperationContract]
bool InitFileRequest(ref FileXferCargo fileRequest);
[OperationContract]
bool InitGetFilePart(ref FileXferCargo fileCargo);
[OperationContract]
Stream GetFilePart(FileXferCargo fileCargo);
[OperationContract]
int CloseFile(FileData fileData);
}
Service实现类定义如下;
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
ConcurrencyMode = ConcurrencyMode.Multiple,
UseSynchronizationContext = false)
]
public class LNMediaServerSvc : IFileXferService
{
...
}
【问题讨论】:
-
在服务和客户端上开启 WCF 跟踪:msdn.microsoft.com/en-us/library/ms733025.aspx
-
在基于 HTTP 的托管的情况下,问题将很明显 - FileData 包含 Stream。在 Net.Tcp 中,我不确定这是否允许。
-
该 Stream 成员仅用于“本地”在几个方法之间携带 Stream。不久前我发现我无法以这种方式返回流,因此有 2 个 Init 方法,然后是 GetFilePart,它是返回实际 Stream 的方法。
-
但流仍然作为 DataMember 包含在 DataContract 中,在 OperationContract 中用作参数。
-
啊,好吧,我要把它拿出来,看看这是否一直是我的问题。