关于WCF通讯传输,在网络掉包的情况的,很难传输成功

dqy007 2010-01-10 12:57:55
举一个例子:
第一种网络情况,一台计算ping服务器返回500毫秒,但是中间不掉包,它可以在10秒中把服务器一批数据读出来
第二种网络情况,ping 服务器返回10毫秒(应该说比较上面快很多),但是ping的过程中偶尔会掉包,这样导致读取数据的时间竟然达30秒,有时就是读不出来

这种原因,目前我猜想,是WCF传输跟传统的有点区别,它是整块传输的,如果在传输中间掉包,它又要从头重新传,它差不像socket分成小块传,所以导致WCF在网络不稳定情况的大块传输,很难成功

想问一下,有没有解决方案,比如:WCF有什么设置,不是整块传输,可以断点续传之类的??
...全文
631 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
qldsrx 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 dqy007 的回复:]
我目前的压缩类也是在网上找的,不知是不是微软代码,我现在返回数据之前,调用一下,前台收到之后再调用一下,其实也不麻烦,不过你那种方式和我这种方式,效果不知道有没有多少区别,如:压缩比,传输时间,我目前 的理解 就是一个明着压缩,一个是暗中压缩,,呵。
[/Quote]

最大的区别是,你那个是全部一起压缩,我这个是分段压缩,所以显然我的这个占用系统资源少。
dqy007 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 qldsrx 的回复:]
当然编译不过了,因为你少了个GZipEncoder.dll文件,那个系统自带的,是自己写的dll,微软有示例代码,提供了GZipEncoder.dll的开源代码,再根据需求自己修改。
总的来说,你只要引用了GZipEncoder.dll,并且将NetTcpBinding 更换成CustomBinding就行了。因为只有CustomBinding才可以自定义BindingElement,而GZipMessageEncodingBindingElement 就是其中之一的BindingElement,引自GZipEncoder.dll。
[/Quote]
我目前的压缩类也是在网上找的,不知是不是微软代码,我现在返回数据之前,调用一下,前台收到之后再调用一下,其实也不麻烦,不过你那种方式和我这种方式,效果不知道有没有多少区别,如:压缩比,传输时间,我目前 的理解 就是一个明着压缩,一个是暗中压缩,,呵。
qldsrx 2010-01-10
  • 打赏
  • 举报
回复
靠,写错了一段:GZipEncoder.dll文件,那个不是系统自带的
qldsrx 2010-01-10
  • 打赏
  • 举报
回复
当然编译不过了,因为你少了个GZipEncoder.dll文件,那个系统自带的,是自己写的dll,微软有示例代码,提供了GZipEncoder.dll的开源代码,再根据需求自己修改。
总的来说,你只要引用了GZipEncoder.dll,并且将NetTcpBinding 更换成CustomBinding就行了。因为只有CustomBinding才可以自定义BindingElement,而GZipMessageEncodingBindingElement 就是其中之一的BindingElement,引自GZipEncoder.dll。
dqy007 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 qldsrx 的回复:]
引用 8 楼 dqy007 的回复:
我想问一下:我目前后台,是先把Dataset压缩字节传输(5M能压到1M多,效果还是不错的,但是我发现缓冲占用一些时间),如果用流设置传输,是不是压缩后要好点呢,还是直接就dataset???

可以让WCF来边压缩边传输,没必要自己先压缩后传输,我记得我前面一个帖子不是给你看过一段示例代码吗?回想一下,里面是不是
C# codeGZipMessageEncodingBindingElement compBindingElement=new GZipMessageEncodingBindingElement(new BinaryMessageEncodingBindingElement());
这个就是在设置压缩传输,配合流模式就是压缩流啦

这个压缩方式传输,MSDN上有示例代码的,可以直接拿来用,也可以修改下,你要是找不到我发给你也可以
[/Quote]
你上次贴的代码,我调试不通过,有的是引用,有的可能是配置,但是给我的启发很大,我在网上找了一段代码,我自己又根据自己的需要修改了一下,如下:
internal static class ChannelFactoryCreator
{
private static Hashtable channelFactories = new Hashtable();
private static string ServerAddress;
public static ChannelFactory<T> Create<T>(string ServerName)
{
if (string.IsNullOrEmpty(ServerName))
{
throw new ArgumentNullException("ServerName");
}

ChannelFactory<T> channelFactory = null;

if (channelFactories.ContainsKey(ServerName))
{
channelFactory = channelFactories[ServerName] as ChannelFactory<T>;
}

if (channelFactory == null)
{
NetTcpBinding ntb = new NetTcpBinding();
ntb.Security.Mode = SecurityMode.None;
ntb.TransferMode = TransferMode.Streamed;
ntb.MaxBufferSize = 10240000;
ntb.MaxReceivedMessageSize = 10240000;
ntb.ReaderQuotas.MaxArrayLength = 10240000;
ntb.ReaderQuotas.MaxBytesPerRead = 10240000;
ntb.ReaderQuotas.MaxDepth = 20;
ntb.ReaderQuotas.MaxNameTableCharCount = 10240000;
ntb.ReaderQuotas.MaxStringContentLength = 10240000;
ntb.CloseTimeout = TimeSpan.Parse("00:10:00");
ntb.ReceiveTimeout = TimeSpan.Parse("00:10:00");
ntb.SendTimeout = TimeSpan.Parse("00:10:00");
ntb.OpenTimeout = TimeSpan.Parse("00:10:00");
if (string.IsNullOrEmpty(ServerAddress))
{
string filepath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\config.xml";
XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(filepath);
XmlNode xn = XmlDoc.SelectSingleNode("/ClientConfig/ServerInfoList/ServerInfo[@isSelected='1']");
ServerAddress = xn.Attributes["AddressAndPort"].Value.ToString();
}
EndpointAddress ea = new EndpointAddress("net.tcp://" + ServerAddress + ServerName);
channelFactory = new ChannelFactory<T>(ntb, ea);
lock (channelFactories.SyncRoot)
{
channelFactories[ServerName] = channelFactory;
}
}

return channelFactory;
}
}
public class ServiceRealProxy<T> : RealProxy
{
private string _ServerName;
public ServiceRealProxy(string ServerName)
: base(typeof(T))
{
if (string.IsNullOrEmpty(ServerName))
{
throw new ArgumentNullException("ServerName");
}
this._ServerName = ServerName;
}

public override IMessage Invoke(IMessage msg)
{
T channel = ChannelFactoryCreator.Create<T>(this._ServerName).CreateChannel();
IMethodCallMessage methodCall = (IMethodCallMessage)msg;
IMethodReturnMessage methodReturn = null;
object[] copiedArgs = Array.CreateInstance(typeof(object), methodCall.Args.Length) as object[];
methodCall.Args.CopyTo(copiedArgs, 0);
try
{
object returnValue = methodCall.MethodBase.Invoke(channel, copiedArgs);
methodReturn = new ReturnMessage(returnValue, copiedArgs, copiedArgs.Length, methodCall.LogicalCallContext, methodCall);
(channel as ICommunicationObject).Close();
}
catch (Exception ex)
{
if (ex.InnerException is CommunicationException || ex.InnerException is TimeoutException)
{
(channel as ICommunicationObject).Abort();
}

if (ex.InnerException != null)
{
methodReturn = new ReturnMessage(ex.InnerException, methodCall);
}
else
{
methodReturn = new ReturnMessage(ex, methodCall);
}
}

return methodReturn;
}
}
public static class ServiceProxyFactory
{
public static T Create<T>(string ServerName)
{
if (string.IsNullOrEmpty(ServerName))
{
throw new ArgumentNullException("ServerName");
}
return (T)(new ServiceRealProxy<T>(ServerName).GetTransparentProxy());
}
}

如果用自带的压缩在哪里修改?或者说在哪里插入一段代码?我前台不用配置文件,后台用配置文件
qldsrx 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 dqy007 的回复:]
我想问一下:我目前后台,是先把Dataset压缩字节传输(5M能压到1M多,效果还是不错的,但是我发现缓冲占用一些时间),如果用流设置传输,是不是压缩后要好点呢,还是直接就dataset???
[/Quote]
可以让WCF来边压缩边传输,没必要自己先压缩后传输,我记得我前面一个帖子不是给你看过一段示例代码吗?回想一下,里面是不是
GZipMessageEncodingBindingElement compBindingElement = new GZipMessageEncodingBindingElement(new BinaryMessageEncodingBindingElement());

这个就是在设置压缩传输,配合流模式就是压缩流啦

这个压缩方式传输,MSDN上有示例代码的,可以直接拿来用,也可以修改下,你要是找不到我发给你也可以
dqy007 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 qldsrx 的回复:]
引用 4 楼 dqy007 的回复:
我说的整块就是缓存模式,如果只是上传下载文件,用流传输,断点续传功能的确 不错。但是用得比较多的是大量dataset传输,这种用断点,好像不太会用


dataset也可以用流传输的,你不需要怎么设断点,你只要像平时一样用,它传输的时候会自动按照流传输的。话说对于数据量较大的dataset,还是用流传输更合适,因为那样就不需要在服务器端缓存一个较大的dataset副本了,客户端也不需要等到数据全部接收完毕才处理。网上有类似的WCF传输大数据DataSet的方案,我看过后感觉直接用流模式传输就可以了,效果更佳。

如果说WCF的数据验证机制是错误后重传,那么缓存模式下的重传肯定是整个请求的重传,而流模式下的重传是有位置的重传,也就是每次发送的那段流数据重传,而不是整个流重传。

最后重申一下,你不需要将DataSet转化为流,只要设置为流模式传输,所有数据自动转换为流进行传输的。
[/Quote]
我想问一下:我目前后台,是先把Dataset压缩字节传输(5M能压到1M多,效果还是不错的,但是我发现缓冲占用一些时间),如果用流设置传输,是不是压缩后要好点呢,还是直接就dataset???
qldsrx 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 dqy007 的回复:]
我说的整块就是缓存模式,如果只是上传下载文件,用流传输,断点续传功能的确 不错。但是用得比较多的是大量dataset传输,这种用断点,好像不太会用
[/Quote]

dataset也可以用流传输的,你不需要怎么设断点,你只要像平时一样用,它传输的时候会自动按照流传输的。话说对于数据量较大的dataset,还是用流传输更合适,因为那样就不需要在服务器端缓存一个较大的dataset副本了,客户端也不需要等到数据全部接收完毕才处理。网上有类似的WCF传输大数据DataSet的方案,我看过后感觉直接用流模式传输就可以了,效果更佳。

如果说WCF的数据验证机制是错误后重传,那么缓存模式下的重传肯定是整个请求的重传,而流模式下的重传是有位置的重传,也就是每次发送的那段流数据重传,而不是整个流重传。

最后重申一下,你不需要将DataSet转化为流,只要设置为流模式传输,所有数据自动转换为流进行传输的。
messi_yang 2010-01-10
  • 打赏
  • 举报
回复
不了解哦
帮顶啊····
dqy007 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 sp1234 的回复:]
你把WCF用低级的逻辑来理解了。TCP本来就是把大包拆成成百上千的小包传输,然后才汇聚的。所以你对
WCF的断言大概是玩底层概念时不小心造成的多心、缺乏测试。
[/Quote]
WCF内部是怎么传输被封装了,我太清楚,但是我上面的二种网络情况是存在的,我想知道是什么原因??
dqy007 2010-01-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 qldsrx 的回复:]
理论上TCP/IP丢包是会自动重传的,所以应该不会很慢的。至于你所说的整块传输是缓存模式吧,数据大点的情况最好使用流模式传输,一段段获取数据,就算传输中有什么问题,也不需要整块重传,流传输是有断点功能的。
[/Quote]
我说的整块就是缓存模式,如果只是上传下载文件,用流传输,断点续传功能的确 不错。但是用得比较多的是大量dataset传输,这种用断点,好像不太会用
  • 打赏
  • 举报
回复
你把WCF用低级的逻辑来理解了。TCP本来就是把大包拆成成百上千的小包传输,然后才汇聚的。所以你对
WCF的断言大概是玩底层概念时不小心造成的多心、缺乏测试。
qldsrx 2010-01-10
  • 打赏
  • 举报
回复
理论上TCP/IP丢包是会自动重传的,所以应该不会很慢的。至于你所说的整块传输是缓存模式吧,数据大点的情况最好使用流模式传输,一段段获取数据,就算传输中有什么问题,也不需要整块重传,流传输是有断点功能的。
tzs2304 2010-01-10
  • 打赏
  • 举报
回复
up

110,566

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧