我注意到的问题是,当客户端通过互联网连接到服务端时,几分钟后服务端的响应变慢,回复变得滞后。我得出结论,当服务端主机的上传容量达到上限(互联网上传速度,在服务器上只有大约15KB / s时),其他客户端发送的消息将被缓冲并在有带宽可用时进行处理。 我想知道如何限制服务使用的缓冲区大小以存储从客户端接收到的消息?对于我的客户端来说,获取所有数据并不那么关键,而是获取其他人发送的最新数据,因此我正在寻找实时连接,即以保证交付为代价。
简而言之,我想能够在服务端填满队列/缓冲区时清理它,或者达到某个上限时开始再次填充它,以消除延迟。我该怎么做?服务端和客户端是否需要减少MaxBufferSize属性?还是我需要在我的服务中编写此功能?有什么想法?
谢谢。
编辑:
这是我的服务架构:
//the service
[ServiceContract(Namespace = "", CallbackContract = typeof(INewsNotification))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public class NewsService
{
private static Dictionary<IChatNotification, string> clients = new Dictionary<IChatNotification, string>();
private ReaderWriterLockSlim subscribersLock = new ReaderWriterLockSlim();
[OperationContract(IsOneWay = true)]
public void PublishNotifications(byte[] data)
{
try
{
subscribersLock.EnterReadLock();
List<INewsNotification> removeList = new List<INewsNotification>();
lock (clients)
{
foreach (var subscriber in clients)
{
if (OperationContext.Current.GetCallbackChannel<IChatNotification>() == subscriber.Key)
{
continue;
}
try
{
subscriber.Key.BeginOnNotificationSend(data, GetCurrentUser(), onNotifyCompletedNotificationSend, subscriber.Key);
}
catch (CommunicationObjectAbortedException)
{
removeList.Add(subscriber.Key);
}
catch (CommunicationException)
{
removeList.Add(subscriber.Key);
}
catch (ObjectDisposedException)
{
removeList.Add(subscriber.Key);
}
}
}
foreach (var item in removeList)
{
clients.Remove(item);
}
}
finally
{
subscribersLock.ExitReadLock();
}
}
}
//the callback contract
[ServiceContract]
public interface INewsNotification
{
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginOnNotificationSend(byte[] data, string username, AsyncCallback callback, object asyncState);
void EndOnNotificationSend(IAsyncResult result);
}
服务配置如下:
<system.serviceModel>
<extensions>
<bindingExtensions>
<add name="pollingDuplex" type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement, System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentSessions="2147483647" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<pollingDuplex>
<binding name="myPollingDuplex" duplexMode="SingleMessagePerPoll"
maxOutputDelay="00:00:00" inactivityTimeout="02:00:00"
serverPollTimeout="00:55:00" sendTimeout="02:00:00" openTimeout="02:00:00"
maxBufferSize="10000" maxReceivedMessageSize="10000" maxBufferPoolSize="1000"/>
</pollingDuplex>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="NewsNotificationService.Web.NewsService">
<endpoint address="" binding="pollingDuplex" bindingConfiguration="myPollingDuplex" contract="NewsNotificationService.Web.NewsService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
客户端通常会在500毫秒到1000毫秒之间调用服务,方法如下:
_client.PublishNotificationAsync(byte[] data);
回调函数会通知客户端其他客户端发送的通知:void client_NotifyNewsReceived(object sender, NewsServiceProxy.OnNewsSendReceivedEventArgs e)
{
e.Usernamer//WHich client published the data
e.data//contents of the notification
}
因此,简而言之,当客户端数量增加,并且服务主机通过互联网的上传速度受限时,由服务发送给订阅者的消息将被缓存在某个地方并在队列中进行处理,这就是问题的根源。我不知道这些消息被缓存在哪里。在局域网中,服务工作正常,因为服务器的上传速度等于其下载速度(对于100KB/s的来电,它会发送100KB/s的通知)。这些消息被缓存在哪里?如何清除此缓冲区?
我尝试了一些实验来查看这些消息是否被缓存在服务中,我尝试在客户端调用此方法,但即使一个客户端仍在接收他人4-5分钟前发送的通知,它也始终返回0:
[OperationContract(IsOneWay = false)]
public int GetQueuedMessages()
{
return OperationContext.Current.OutgoingMessageHeaders.Count();
}