2013-01-23 3 views
18

현재 WCF 자체 호스팅 서비스 (IIS 없음)를 사용하여 대용량 데이터를 보내려고하는 중 문제가 발생합니다. 내 서비스가 System.OutOfMemoryException과 충돌하여 스트리밍 결과를 사용하여 500MB를 전송 중입니다. 그런 양의 데이터를 전송할 수 있습니까? 여기 WCF 자체 호스팅 서비스에서 큰 데이터 (500MB/1GB) 스트리밍

내 WCF 구성입니다 :

<system.serviceModel> 
<services> 
    <service name="CIService" behaviorConfiguration="CIBehavior">   
    <host> 
     <baseAddresses> 
     <add baseAddress="net.tcp://localhost:6547/CIService/CIService.svc" /> 
     </baseAddresses> 
    </host> 
    <endpoint binding="netTcpBinding" 
     bindingConfiguration="netTcpBindingConfig" 
     behaviorConfiguration="CIBehavior.EndpointBehavior" 
     contract="CIService.ICreatable" /> 
    <endpoint address="mex" 
     binding="mexHttpBinding" 
     name="mexTcpBinding" 
     contract="IMetadataExchange" /> 
    </service> 
</services> 
<serviceHostingEnvironment multippleSiteBindingEnabled="True" /> 
<bindings> 
    <netTcpBinding> 
    <binding name="netTcpBindingConfig" closeTimeout="00:01:00" openTimeout="00:01:00" 
     receiveTimeout="01:00:00" sendTimeout="00:10:00" 
     hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxConnections="10" 
     maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647" 
     transferMode="Streamed"> 
     <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" 
     maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" /> 
    </binding> 
    </netTcpBinding> 
</bindings> 

<behaviors> 
    <serviceBehaviors> 
    <behavior name="CIBehavior"> 
     <serviceMetadata httpGetEnabled="False" /> 
     <serviceDebug includeExceptionDetailInFaults="true" /> 
     <serviceThrottling maxConcurrentCalls="200" maxConcurrentInstances="2147483647" maxConcurrentSessions="100" /> 
     <dataContractSerializer maxItemsInObjectGraph="2147483647"/> 
    </behavior> 
    </serviceBehaviors> 
    <endpointBehavior> 
    <behavior name="CIBehavior.EndpointBehavior"> 
     <dataContractSerializer maxItemsInObjectGraph="2147483647" /> 
    </behavior> 
    </endpointBehavior> 
</behaviors> 
</system.serviceModel> 

내 클라이언트 구성 :

<system.serviceModel> 
<bindings> 
    <netTcpBinding> 
    <binding name="NetTcpBinding_ICreatable" 
      closeTimeout="00:01:00" openTimeout="00:01:00" 
      receiveTimeout="01:00:00" sendTimeout="00:10:00" 
      transactionFlow="false" 
      transferMode="Streamed" 
      transactionProtocol="OleTransactions" 
      hostNameComparisonMode="StrongWildcard" 
      listenBacklog="10" 
      maxBufferPoolSize="2147483647" 
      maxBufferSize="2147483647" 
      maxConnections="10" 
      maxReceivedMessageSize ="2147483647"> 
     <readerQuotas 
     maxDepth="2147483647" 
     maxStringContentLength="2147483647" 
     maxArrayLength="2147483647" 
     maxBytesPerRead="2147483647" 
     maxNameTableCharCount="2147483647" /> 
     <reliableSession ordered="true" inactivityTimeout="00:10:00" anabled="false" /> 
    </binding> 
    </netTcpBinding> 
</bindings> 
<client> 
    <endpoint name="NetTcpBinding_ICreatable" 
     address="net.tcp://localhost:6547/CIService/CIService.svc" 
     binding="netTcpBinding" 
     bindingConfiguration="NetTcpBinding_ICreatable" 
     behaviorConfiguration="CIBehavior.EndpointBehavior" 
     contract="ICreatable" /> 
</client> 
<behaviors> 
    <endpointBehavior> 
    <behavior name="CIBehavior.EndpointBehavior"> 
     <dataContractSerializer maxItemsInObjectGraph="2147483647" /> 
    </behavior> 
    </endpointBehavior> 
</behaviors> 
</system.serviceModel> 
+1

데이터를 더 작은 조각으로 덩어리로 만들어야합니다. – TGlatzer

+0

대용량 메시지를 확실히 전송할 수 있습니다. http://orand.blogspot.fr/2007/12/wcf-message-size-tester.html을 참조하십시오. –

답변

35

당신이 가능하게 메모리 예외 당신의 아웃 일으키는 너무 높게 설정 maxBufferPoolSize해당 MaxBufferSize 또는 을 필요 없어요 . 기본값은 잘되어야합니다. 대형 데이터 텍스트의이 작품에 대한 MSDN에

체크 아웃 Large Data and Streaming, 특히 섹션 특별 보안 고려 사항은 해당 MaxBufferSize 속성은 메모리가 WCF 버퍼를 제한 할 필요

중요하다. 스트리밍 할 때 이것을 안전한 값으로 설정하거나 (기본값 : 으로 유지하는 것) 중요합니다. 예를 들어 서비스가 최대 4GB의 파일을 받아서 로컬 디스크에 저장해야한다고 가정합니다. 또한 메모리가 한 번에 64KB의 데이터 만 버퍼링 할 수있는 방식으로 제한되어 있다고 가정합니다. 그런 다음 MaxReceivedMessageSize를 4GB로, MaxBufferSize를 64KB로 설정합니다. 또한 서비스 구현에서 서비스를 구현하려면 들어오는 스트림에서 64KB 청크로만 을 읽고 다음 번에 청크를 읽지 않도록하십시오. 이전 청크가 디스크에 쓰여지고 메모리에서 이 삭제됩니다.

나는 자체 호스팅 서비스에서 콘솔 클라이언트로 데이터를 스트리밍하는 간단한 예제를 작성했습니다. 게시물을 짧게 유지하려면 서버 코드와 클라이언트의 일부만 추가했습니다.

서비스 계약

using System.IO; 
using System.ServiceModel; 

namespace Service 
{ 
    [ServiceContract] 
    public interface IStream 
    { 
     [OperationContract] 
     Stream GetLargeObject(); 
    } 
} 

서비스 구현

using System; 
using System.IO; 
using System.ServiceModel; 

namespace Service 
{ 
    [ServiceBehavior] 
    public class StreamService : IStream 
    { 
     public Stream GetLargeObject() 
     { 
      // Add path to a big file, this one is 2.5 gb 
      string filePath = Path.Combine(Environment.CurrentDirectory, "C:\\Temp\\BFBC2_PC_Client_R11_795745_Patch.exe"); 

     try 
     { 
      FileStream imageFile = File.OpenRead(filePath); 
      return imageFile; 
     } 
     catch (IOException ex) 
     { 
      Console.WriteLine(String.Format("An exception was thrown while trying to open file {0}", filePath)); 
      Console.WriteLine("Exception is: "); 
      Console.WriteLine(ex.ToString()); 
      throw; 
     } 
    } 
} 
} 

주요 서비스

using System; 
using System.ServiceModel; 

namespace Service 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       using (var serviceHost = new ServiceHost(typeof(StreamService))) 
       { 
        serviceHost.Open(); 

        Console.WriteLine("Press Any Key to end"); 
        Console.ReadKey(); 
       } 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex.ToString()); 
      } 
     } 
    } 
} 

서비스의 app.config

<?xml version="1.0"?> 
<configuration> 
    <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
    </startup> 

    <system.serviceModel> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="StreamServiceBehavior"> 
      <serviceMetadata httpGetEnabled="True" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <bindings> 
     <netTcpBinding> 
     <binding name="NewBinding0" transferMode="Streamed"/> 
     </netTcpBinding> 
    </bindings> 
    <services> 
     <service behaviorConfiguration="StreamServiceBehavior" name="Service.StreamService"> 
     <endpoint address="net.tcp://localhost:9000/streamserver" binding="netTcpBinding" 
      bindingConfiguration="NewBinding0" bindingName="" contract="Service.IStream" /> 
     <endpoint address="mex" binding="mexHttpBinding" 
      contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="http://localhost:8080/StreamService" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    </system.serviceModel> 
</configuration> 

서비스를 시작하고 소켓 계정을 열려면 관리자 계정으로 실행해야 할 수 있습니다. 클라이언트 콘솔 응용 프로그램을 만들고 url http : // localhost : 8080/StreamService를 사용하여 서비스 참조를 추가합니다. Service는 생성 된 클라이언트의 네임 스페이스로 사용합니다.

using System; 
using System.IO; 
using Client.Service; 

namespace Client 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try 
      { 
       using (StreamClient streamClient = new StreamClient()) 
       { 
        streamClient.Open(); 

        using (FileStream fileStream = new FileStream("c:\\temp\\bigfile.exe",FileMode.Create)) 
        { 
         streamClient.GetLargeObject().CopyTo(fileStream);  
        } 
       } 

       Console.WriteLine("Press any key to end"); 
       Console.ReadKey(); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine(ex); 
      } 
     } 
    } 
} 

생성 된 클라이언트 설정 파일을 약간 수정해야합니다 주요 클라이언트, 다음 maxReceivedMessageSize = "4294967295"

<system.serviceModel> 
    <bindings> 
     <netTcpBinding> 
      <binding name="NetTcpBinding_IStream" closeTimeout="00:01:00" 
       openTimeout="00:01:00" receiveTimeout="00:30:00" sendTimeout="00:01:00" 
       transactionFlow="false" transferMode="Streamed" transactionProtocol="OleTransactions" 
       hostNameComparisonMode="StrongWildcard" listenBacklog="10" 
       maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" 
       maxReceivedMessageSize="4294967295"> 
       <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
        maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
       <reliableSession ordered="true" inactivityTimeout="00:10:00" 
        enabled="false" /> 
       <security mode="Transport"> 
        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> 
        <message clientCredentialType="Windows" /> 
       </security> 
      </binding> 
     </netTcpBinding> 
    </bindings> 
    <client> 
     <endpoint address="net.tcp://localhost:9000/streamserver" binding="netTcpBinding" 
      bindingConfiguration="NetTcpBinding_IStream" contract="Service.IStream" 
      name="NetTcpBinding_IStream"> 

     </endpoint> 
    </client> 
</system.serviceModel> 

실행 서비스 receiveTimeout 증가 및 설정 클라이언트. 큰 파일을 문제없이 스트리밍합니다.

관련 문제