C#中使用HttpWebRequest中如何避免TCP重传?

skywshing 2017-08-21 05:40:47
应用场景:
应用程序提交订单至供货商api接口,出现了提交订单请求执行一次,供货商服务端收到2笔相同订单的情况.
经过查阅相关资料,猜测为TCP重传导致.这是应用程序无法控制的.
资料说明如下:
由于设置了链接和获取数据的超时时间,客户端在发送数据之后,检测到可能没有发送成功到后端,这个时候http底层会自动重发请求(注意是http底层,所以应用程序不知道发送了多少次请求).并给出了java代码的解决办法:
defaultHttpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0,false));

那在C#中该如何避免这种情况呢?
TCP重传的目的就是为了保证数据的送达率,但是在上述应用场景中如果供货商系统未对订单号做任何限制的话,那就相当于提交1笔订单,他们会销售多笔订单,从而造成亏损.

以下为C#代码:

try
{
var request = (HttpWebRequest)WebRequest.Create(url);
request.CookieContainer = _webCookieContainer;
request.Timeout = 30000;
request.ReadWriteTimeout = 30000;
request.UserAgent = _userAgent;
request.Referer = _referer;
if (proxy != null) request.Proxy = proxy;
if (!_keepAlive)
{
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version11;
}
var response = (HttpWebResponse)request.GetResponse();
var recvStream=response.GetResponseStream();
if (recvStream != null)
{
var reader = new StreamReader(recvStream, enc);
result = reader.ReadToEnd();
}
_lastUrl = response.ResponseUri.ToString();
response.Close();
request.Abort();
}
catch (Exception ex)
{
result = ex.Message;
}
...全文
621 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
泡泡龙 2017-08-23
  • 打赏
  • 举报
回复
如果找不到原因,就从逻辑上避免它。找个统一的唯一的发送类,在里面做个重复检查,确认是不是真的没有重复发送。
游北亮 2017-08-23
  • 打赏
  • 举报
回复
tcp重传,不会导致客户端收到2次, 什么叫可靠?tcp重传,客户端即使接收到2次,也会抛弃掉其中一次 你认真研讨一下tcp协议吧, 如果真有这种问题,internet早就乱套了,不用等你来提问
skywshing 2017-08-22
  • 打赏
  • 举报
回复
引用 12 楼 ilikeff8 的回复:
http底层如果超时重发tcp请求,也是只会收到最后一条 我业务上就应该设计成允许反复发送同样的订单,不管是超时重发整个TCP请求,还是人为多次点击发送,有个应答机制,发过去后,客户端收到后返回接收信号,至少要再收到同样的订单号或流水号不再处理 如果供应商那边不能修改接收代码,则在你发送TCP请求的地方写日志记录吧
感谢您对该问题的关注! 只有在发送http请求的时候记录了请求和响应, 不清楚如何在发送TCP请求的地方写日志,麻烦详细描述一下
ilikeff8 2017-08-22
  • 打赏
  • 举报
回复
http底层如果超时重发tcp请求,也是只会收到最后一条 我业务上就应该设计成允许反复发送同样的订单,不管是超时重发整个TCP请求,还是人为多次点击发送,有个应答机制,发过去后,客户端收到后返回接收信号,至少要再收到同样的订单号或流水号不再处理 如果供应商那边不能修改接收代码,则在你发送TCP请求的地方写日志记录吧
skywshing 2017-08-22
  • 打赏
  • 举报
回复
引用 7 楼 m0_37700861 的回复:
[quote=引用 5 楼 ilikeff8 的回复:] tcp是可靠连接,不会反复发的,路由器在丢包的时候才会重发,而且保证组包后用户只会收到一次,应该是程序里再重复发送
.net区就是一片废墟。[/quote] .net core2.0发布了,要有信心! 没有一样技术是永远长青的,但是拥抱变化,拥抱学习是程序员要永远坚持的理念.
skywshing 2017-08-22
  • 打赏
  • 举报
回复
引用 9 楼 a755362405 的回复:
日志,日志,做好日志,就可以对照了。你说没点2次,要是有人点2次你知道? 其次,就算是TCP重传,前一个数据包也是无效的,不会发生插入2次的情况。
感谢您对该问题的关注! 执行get请求的代码已经贴出来了.执行前后也都打印日志了,确定没有多次执行http请求. 因为应用程序是通过httpwebrequest获取到订单,再通过httpwebrequest去提交订单,没有前端页面给用户点击,所以不会出现有人点击2次的情况. 您说的"就算是TCP重传,前一个数据包也是无效的,不会发生插入2次的情况",我就不清楚是否这种情况造成了,所以发到社区请教一下各位.
键盘敲出字 2017-08-22
  • 打赏
  • 举报
回复
日志,日志,做好日志,就可以对照了。你说没点2次,要是有人点2次你知道? 其次,就算是TCP重传,前一个数据包也是无效的,不会发生插入2次的情况。
skywshing 2017-08-22
  • 打赏
  • 举报
回复
引用 5 楼 ilikeff8 的回复:
tcp是可靠连接,不会反复发的,路由器在丢包的时候才会重发,而且保证组包后用户只会收到一次,应该是程序里再重复发送
感谢您对该问题的关注! 程序确定是没有重复发送的,执行get请求的代码已经贴出来了.执行前后也都打印日志了,确定没有多次执行http请求. 我的想法,是tcp在发送数据包的时候,已经发送的服务端了,但是因为读取超时等原因,认为并没有发送成功,就导致了超时重传的机制生效,从而导致了这种问题.
m0_37700861 2017-08-22
  • 打赏
  • 举报
回复
引用 5 楼 ilikeff8 的回复:
tcp是可靠连接,不会反复发的,路由器在丢包的时候才会重发,而且保证组包后用户只会收到一次,应该是程序里再重复发送
.net区就是一片废墟。
skywshing 2017-08-22
  • 打赏
  • 举报
回复
引用 3 楼 diaodiaop 的回复:
引用
经过查阅相关资料,猜测为TCP重传导致.这是应用程序无法控制的.
你查了什么资料?你能告诉我一下吗? 另外 http请求跟tcp/ip协议 有什么关系 你知道吗? 既然你说"应用程序无法控制" 为什么只有你遇到这种问题 而我们都没有遇到(你可以理解我见识少).
引用
这个时候http底层会自动重发请求(注意是http底层,所以应用程序不知道发送了多少次请求)
根据你的说法 你自己写一个http服务器 然后写一个http客户端 我看你是如何"自动发送请求"的 你能写出模拟代码来吗? coder....请开始你的表演.... 另外说到正题.. 你的问题 基本就是" 点了一下发现没反映又点了一下导致提交了2次" ....
感谢您对该问题的关注! 下面,那我开始我的表演了~ http是tcp/ip协议中四层的应用层,处于该层的还有ftp等协议. 一个http请求过来后,会经过传输层(tcp/udp)以数据包的形式传递到网络层(ip),再到链路层,最后取到的数据(响应报文)再按照这个层级返回到应用层. 因为应用程序是通过httpwebrequest获取到订单,再通过httpwebrequest去提交订单,应用场景中是不存在"点了一下发现没反映又点了一下导致提交了2次"的情况. 我的猜测是在tcp传递数据包时,因为存在超时重传的机制,有可能针对同一个数据包传递多次到服务端. 这种情况是机率发生的,按照目前我们一个月三千万级别的订单量计算,发生的概率在千万分之一左右,所以稳定重现的难度可想而知. 如果我自己写个http服务器,写个客户端就能重现出来的话,估计我就解决这个问题了.
ilikeff8 2017-08-22
  • 打赏
  • 举报
回复
tcp是可靠连接,不会反复发的,路由器在丢包的时候才会重发,而且保证组包后用户只会收到一次,应该是程序里再重复发送
skywshing 2017-08-22
  • 打赏
  • 举报
回复
引用 1 楼 sp1234 的回复:
[quote=引用 楼主 skywshing 的回复:] 应用场景: 应用程序提交订单至供货商api接口,出现了提交订单请求执行一次,供货商服务端收到2笔相同订单的情况. 经过查阅相关资料,猜测为TCP重传导致.这是应用程序无法控制的.
我没有听说过还有这种理由。 这是对 bug 的借口。通过 tcp 收到的消息不会多出什么字节来,更不会那么恰好地多出(分包、粘包之后还)一个业务消息。[/quote] 感谢您对该问题的关注. 因为TCP本身是有超时重传的机制用来保证数据的可靠性,所以我不认为是tcp传递数据多出来的数据包,而是因为tcp针对同一个数据包的多次发送造成. 执行的代码也贴出来了,参数url就是我要get的url串. 但是,我看不出有啥bug.....
by_封爱 版主 2017-08-22
  • 打赏
  • 举报
回复
引用
经过查阅相关资料,猜测为TCP重传导致.这是应用程序无法控制的.
你查了什么资料?你能告诉我一下吗? 另外 http请求跟tcp/ip协议 有什么关系 你知道吗? 既然你说"应用程序无法控制" 为什么只有你遇到这种问题 而我们都没有遇到(你可以理解我见识少).
引用
这个时候http底层会自动重发请求(注意是http底层,所以应用程序不知道发送了多少次请求)
根据你的说法 你自己写一个http服务器 然后写一个http客户端 我看你是如何"自动发送请求"的 你能写出模拟代码来吗? coder....请开始你的表演.... 另外说到正题.. 你的问题 基本就是" 点了一下发现没反映又点了一下导致提交了2次" ....
wang_peng_yl 2017-08-22
  • 打赏
  • 举报
回复
你这种事我还第一次听说,如果方便,加我QQ: 274941173 我帮你调一下,应该是逻辑的问题,加的时候说是csdn上的
  • 打赏
  • 举报
回复
引用 楼主 skywshing 的回复:
应用场景: 应用程序提交订单至供货商api接口,出现了提交订单请求执行一次,供货商服务端收到2笔相同订单的情况. 经过查阅相关资料,猜测为TCP重传导致.这是应用程序无法控制的.
我没有听说过还有这种理由。 这是对 bug 的借口。通过 tcp 收到的消息不会多出什么字节来,更不会那么恰好地多出(分包、粘包之后还)一个业务消息。

110,539

社区成员

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

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

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