Пожалуйста, не закрывайте дубликаты, пока вы не прочитаете вопрос до конца; Я уже много часов работал без работы.
EDIT: Теперь я убежден, что это связано с тем, как кэши WCF открывали TCP-соединения (пул соединений). Пожалуйста, взгляните на правление № 5 в конце вопроса.
У меня в основном есть служба WCF, которая использует конфигурацию netTcpBinding
. Даже если я закрываю клиентский прокси изящно (см. Код ниже), сервер всегда регистрирует "System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host
".
Я сузил проблему до самого основного примера WCF, который я мог написать. Я получаю исключение в журналах, созданных трассировкой WCF каждый раз, когда я закрываю клиентское приложение. Я не получаю никаких исключений в своем собственном коде, но это означает, что он работает так, как ожидалось, и я не могу отлаживать что-либо, чтобы увидеть, что не так для WCF, чтобы добавить ошибку в мои журналы.
Сервисный интерфейс/реализация:
[ServiceContract]
public interface IService1
{
[OperationContract]
string DoWork();
}
...
public class Service1 : IService1
{
public string DoWork()
{
return "12";
}
}
Конфигурация на стороне сервера:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="WebApplication1.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="netTcpEndpointBinding" contract="WebApplication1.IService1" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="netTcpEndpointBinding">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
Конфигурация на стороне клиента:
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IService1">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost/WebApplication1/Service1.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IService1"
contract="ServiceReference1.IService1" name="NetTcpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>
Клиентский код, который использует эту услугу (VS2012 сгенерировал прокси-сервер клиента для меня, используя "Добавить ссылку на службу" ):
private async Task<string> TestTask()
{
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy.State != System.ServiceModel.CommunicationState.Faulted)
{
Console.WriteLine("Closing client");
proxy.Close();
}
else
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
}
}
Все работает нормально:
Calling service
Закрывающий клиент
12
Но как только приложение завершается, сервер регистрирует исключение. Я понимаю, что я не должен беспокоиться об этом исключении, потому что он работает так, как ожидалось (исключение появляется только в журналах), и может случиться так или иначе, если клиент будет прекращен до вызова .Close()
/.Abort()
.
Но все-таки, это нормальное поведение? Я имею в виду, что если я правильно закрываю свой клиентский прокси, я ожидаю, что сервер будет не регистрировать исключение (которое загрязняет мои журналы). Я также предполагаю, что некоторое TCP-соединение по-прежнему устанавливается между клиентом и сервером (неизвестное состояние) после закрытия клиентского прокси, поскольку сервер регистрирует исключение только после завершения всего клиентского приложения. Если такое соединение все еще открыто, не может ли это ввести непредвиденное поведение (например, максимальное количество подключенных клиентов)? Это действительно ожидалось?
Я нашел разные темы по этой проблеме:
wcf "существующее соединение было принудительно закрыто удаленным хостом" после закрытия клиента
Вывод будет "не заботится об этом".
Может ли кто-нибудь подтвердить это с некоторыми ссылками и объяснить, почему это исключение все равно?
EDIT:
Трассировка журнала исключения:
<Exception>
<ExceptionType>System.Net.Sockets.SocketException, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>An existing connection was forcibly closed by the remote host</Message>
<StackTrace>
à System.ServiceModel.Channels.SocketConnection.HandleReceiveAsyncCompleted()
à System.ServiceModel.Channels.SocketConnection.OnReceiveAsync(Object sender, SocketAsyncEventArgs eventArgs)
à System.Net.Sockets.SocketAsyncEventArgs.FinishOperationAsyncFailure(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
à System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
à System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<ExceptionString>System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host</ExceptionString>
<NativeErrorCode>2746</NativeErrorCode>
</Exception>
Спасибо большое
ИЗМЕНИТЬ 2: У меня такая же проблема при размещении службы в IIS или при ее самообслуживании в службе Windows
ИЗМЕНИТЬ 3: здесь полный пример для воспроизведения проблемы: http://speedy.sh/ENB59/wcf-test.zip
ИЗМЕНИТЬ 4:
Я попытался контролировать то, что на самом деле происходит под капотом, с TCP-соединением WCF для меня.
После закрытия прокси-сервера клиента я все еще вижу открытое TCP-соединение с моим сервером:
Я предполагаю, что это связано с кэшированием TCP-соединения для последующего повторного использования (например, пула соединений), поскольку открытие нового подключения к серверу (после того, как первый клиентский прокси был закрыт) не создает новое TCP-соединение. Если я дважды вызываю Console.WriteLine(new Test().TestTask().Result);
в моем приложении, я вижу только одно открытое TCP-соединение.
Я также отметил, что это соединение умирает из-за таймаута, если я слишком долго жду закрытия клиентского канала.
РЕДАКТИРОВАТЬ 5: ОК, я нашел документацию по MSDN об этом пуле соединений:
NetTcpBinding использует пул соединений TCP на основе сервисов DNS-имя хоста и номер порта, который прослушивает служба. Эта хорошо работает, когда клиент совершает звонки на различные услуги по разные порты или службы размещаются в одном процессе и совместно используются порт. Если один клиент вызывает несколько служб, разделяющих порт, который размещаются в разных процессах или размещаются WAS/IIS, клиент боковое объединение может привести к проблемам, когда соединение с сервисом A повторно используется для обслуживания B, в результате чего создается исключение, соединение прервано, и создан новый канал. Чтобы избежать этой проблемы, используйте CustomBinding и укажите другое ConnectionPoolSettings.GroupName для каждой службы клиент общается с.
Итак, теперь мой вопрос: если это нормальное поведение, что я могу сделать, чтобы предотвратить загрязнение моего журнала всеми этими исключениями?