TCP Socket Sending Delays and Retransmission - c#

I have a .NET 3.5 C# application that sends 2000-6000 byte packets to a linux machine running sles 10. The machines are on the same subnet.
About 90% of the time, everything works fine. The linux machine processes my request and responds in 5-15ms. But about 10% of the time, there is an approx 200ms-800ms delay.
Looking at the logs on the linux machine, it seems the delay is on my end. That is, if my call to socket.Send(...) returns at 1:15:00.000 and I get a response at 1:15:00.210, the log on the linux machine says that it received the request at 1:15:00.200 and then processed it in 10ms. (I'm using System.Diagnostics.Stopwatch for timing on my machine.)
To debug, I captured the traffic using wireshark. Here is the traffic. Between No. 8 and 9 is where a 600 ms delay occurs. (137.34.210.108 is my machine and 137.34.210.95 is the linux machine).
"1","11:56:27.380318","137.34.210.95","137.34.210.108","TCP","20700 > 17479 [PSH, ACK] Seq=1 Ack=1 Win=32767 Len=76"
"2","11:56:27.380393","HewlettP_29:37:0f","Broadcast","ARP","Who has 137.34.210.95? Tell 137.34.210.108"
"3","11:56:27.380558","HewlettP_29:39:93","HewlettP_29:37:0f","ARP","137.34.210.95 is at 00:1b:78:29:39:93"
"4","11:56:27.380564","137.34.210.108","137.34.210.95","TCP","17479 > 20700 [ACK] Seq=1 Ack=77 Win=65459 [TCP CHECKSUM INCORRECT] Len=0"
"5","12:04:48.096892","HewlettP_29:37:0f","Broadcast","ARP","Who has 137.34.210.95? Tell 137.34.210.108"
"6","12:04:48.097216","HewlettP_29:39:93","HewlettP_29:37:0f","ARP","137.34.210.95 is at 00:1b:78:29:39:93"
"7","12:04:48.097229","137.34.210.108","137.34.210.95","TCP","17480 > 20600 [PSH, ACK] Seq=1 Ack=1 Win=64198 [TCP CHECKSUM INCORRECT] Len=458"
"8","12:04:48.097457","137.34.210.95","137.34.210.108","TCP","20600 > 17480 [ACK] Seq=1 Ack=4294964377 Win=32767 Len=0 SLE=1 SRE=459"
"9","12:04:49.700966","137.34.210.108","137.34.210.95","TCP","17479 > 20700 [ACK] Seq=1 Ack=77 Win=65459 [TCP CHECKSUM INCORRECT] Len=1460"
"10","12:04:49.701190","137.34.210.108","137.34.210.95","TCP","[TCP Retransmission] 17480 > 20600 [ACK] Seq=4294964377 Ack=1 Win=64198 [TCP CHECKSUM INCORRECT] Len=1460"
"11","12:04:49.703970","137.34.210.95","137.34.210.108","TCP","20600 > 17480 [ACK] Seq=1 Ack=4294965837 Win=32767 Len=0 SLE=1 SRE=459"
"12","12:04:49.703993","137.34.210.108","137.34.210.95","TCP","[TCP Retransmission] 17480 > 20600 [ACK] Seq=4294965837 Ack=1 Win=64198 [TCP CHECKSUM INCORRECT] Len=1460"
"13","12:04:49.704002","137.34.210.108","137.34.210.95","TCP","[TCP Retransmission] 17480 > 20600 [PSH, ACK] Seq=1 Ack=1 Win=64198 [TCP CHECKSUM INCORRECT] Len=458"
"14","12:04:49.704211","137.34.210.95","137.34.210.108","TCP","20600 > 17480 [ACK] Seq=1 Ack=459 Win=32767 Len=0"
"15","12:04:49.704215","137.34.210.95","137.34.210.108","TCP","[TCP Dup ACK 14#1] 20600 > 17480 [ACK] Seq=1 Ack=459 Win=32767 Len=0 SLE=1 SRE=459"
"16","12:04:49.705425","137.34.210.95","137.34.210.108","TCP","20700 > 17479 [PSH, ACK] Seq=77 Ack=1461 Win=32767 Len=44"
Can someone help me to interpret this? I see that a re-transmit is occurring. But I'm not sure why. The switch shows no dropped packets. And even if the packets are being lost, why would it take 600ms to re-transmit?
I thought that this (http://support.microsoft.com/kb/328890) might have something to do with the 200ms delays but I've tried changing the TcpAckFrequency and it didn't help.
Thanks,
Mike

Let's start by pruning some of that Wireshark output. We can toss the ARPs in packets 2, 3, 5 and 6. Looking at the rest, you have two sets of traffic in there. Packets 8 and 9 are two different connections, so you can't compare them. 7, 8 and 10, however, are part of one connection so let's examine those.
Packet 7 is 458 bytes of data being sent to the Linux box with a TCP sequence number of 1. However, the ACK that the Linux box returns is 4294964377. This means that Wireshark is showing relative TCP values and that the Linux box is not sending an ACK for packet 7, but for an earlier packet. Your PC then waits for a follow-up ACK and, when it doesn't get one, retransmits the required data. In this case the 458 bytes from packet 7 along with a previous 1002 bytes. That's why the sequence number from packet 10 matches the ACK from packet 8.
Unfortunately this doesn't tell you why data is being dropped. Packet 8 shows the Linux box indicating it still has a full 32k of input buffer available for this connection ("Win=32767").

This only shows the TCP packets on the Linux machine, but I'd recommend to look at the ip stats with the 'netstat -s' command. One reason for the retransmissions might be socket buffer overflows, which will be shown with this command.

I don't recall if Windows has it, but on UNIX you'd enable TCP_NODELAY.
This disables TCP's Nagle Algorithm which makes the system wait for a small time in case more data is going to be added to the transmit buffer.
int nodelay = 1;
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay));

Related

Android/Xamarin detect when smart card inserted into USB attached device

Assistance in trying to detect when an actual smart-card is inserted into a USB smart-card reader attached to a handheld Android device.
I have an existing (and completely working) instance of the BroadcastReceiver and am successfully detecting when the actual smart-card reader device is connected via the filters of
myFilter.AddAction(UsbManager.ActionUsbDeviceAttached);
myFilter.AddAction(UsbManager.ActionUsbDeviceDetached);
What I am looking for now is when an actual card is inserted or removed from the device.
By using ADB (Android Debug Bridge) program and using the logcat, I can redirect the output to a file to see what is going on such as
adb logcat -c (to clear log)
adb logcat > c:\SomeFolder\MyAndroidLog.txt
Before starting the log above, I have my handheld device ready, the smart-card reader attached. Immediately after that is when I clear the log and start a fresh capture. Then I insert my smart card, wait a few seconds and then stop the log with Ctrl+C. Upon viewing the log, I am getting
--------- beginning of main
10-07 11:43:26.458 827 827 I chatty : uid=1000(system) /system/bin/surfaceflinger expire 14 lines
10-07 11:43:26.459 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
10-07 11:43:26.861 556 556 W hwservicemanager: getTransport: Cannot find entry vendor.qti.hardware.servicetracker#1.0::IServicetracker/default in either framework or device manifest.
10-07 11:43:26.925 556 556 I chatty : uid=1000(system) hwservicemanage identical 14 lines
10-07 11:43:26.928 556 556 W hwservicemanager: getTransport: Cannot find entry vendor.qti.hardware.servicetracker#1.0::IServicetracker/default in either framework or device manifest.
10-07 11:43:26.930 7529 7529 D BoundBrokerSvc: onUnbind: Intent { act=com.google.android.gms.feedback.internal.IFeedbackService dat=chimera-action:com.google.android.gms.feedback.internal.IFeedbackService cmp=com.google.android.gms/.chimera.GmsBoundBrokerService }
10-07 11:43:27.481 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
10-07 11:43:27.483 827 827 I chatty : uid=1000(system) /system/bin/surfaceflinger identical 2 lines
10-07 11:43:27.484 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
10-07 11:43:27.780 1170 1170 I HSMCOUNTER: Wrote to EEPROM: ret: 0
10-07 11:43:28.444 827 827 I ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
So it is showing some context of a ConfigStore, but nothing that indicates the "intent" action that other activities are capturing such as when the USB device is connected such as:
10-07 12:05:15.068 1512 1828 I ActivityManager: START u0 {act=android.hardware.usb.action.USB_DEVICE_ATTACHED flg=0x11000000 cmp=com.gemalto.gempcsc.gempcscserviceactivity/com.gemalto.gempcsc.gempcscservice.USBBroadcastReceiver (has extras)} from uid 1000
Additionally, if there is a generic way to capture ALL intents going on vs having to manually add all filters and not even knowing what they all COULD be, might help me narrow it down.
You need to talk to the reader using the CCID protocol. See my previous answer.
For example (sequence numbers in bold):
Send PC_to_RDR_GetSlotStatus (message 0x65 for slot 0):
-> 65000000000000000000
And receive RDR_to_PC_SlotStatus (message 0x81):
Example response for no card present:
<- 81000000000000020000
Example response for inserted unpowered card
<- 81000000000000010000
Below is a base-64 encoded wireshark USB trace detecting card in a GemPC Twin Reader(decode it to binary file and open it in Wireshark, then right-click any packet and select "Decode As...", change to "USB Device" tab, select "USBCCID" protocol and click "OK"):
-----BEGIN PCAP-NG CAPTURE FILE-----
H4sIAAAAAAAAA+Pi5eWSYWBg8LXRlmIE0v+hACQG4usA8R0GEGBhYGJgZygtTsrNzzNg4ATKsjFA
AEgNiJ0D5X96xcrA/SrFzgvIBmGGA9Pfnpn0/38wM5MCI4Muw8opHskg4dO6rAy9QLu4gGwuBtwg
FYmdg8WumteYdjkzN6HYZaPPClaP0y4mCNWIxMNml7LHFLhdB8S6FiH7aw3ULuWjbCT4iw2nvxZ7
YtoF8xfMrsXH2EjwFxsjzC5WNLsi2HztGRlkGJzzS/NKUouKFQqK8ssyU1JTFJIqFVJKcwuSEwuY
GDjAas8cN7NjhrIDgPpYgOwUZohZrEA2MgDZAQDbbEGJZAIAAA==
-----END PCAP-NG CAPTURE FILE-----
(Note: Sequence numbers in capture file have holes as packets are extracted from a longer dump)

Packet loss resulting in bad framerate during webrtc call

I am working on a webrtc implementation for uwp using the following sdk: https://github.com/webrtc-uwp/webrtc-uwp-sdk/tree/releases/m71
The implementation generally works fine though I am having some issues with call quality when packet loss occurs. What happens is that when a packet or a few packets are lost framerate decreases a lot. Think from 30 FPS to less than 1 FPS. The audio is fine however. This would not be a problem if my client would recover when connection is improved again. However at this moment, if the problem occurs then the video is bad for the rest of the call.
I do not know where the issue might lay. As I understand it webrtc is supposed to compensate for packet loss? I was thinking that the issue might be in the sdk I am using. When I get a videotrack from the other peer I just connect it to a mediaelement in uwp so I do not handle the incoming frames myself. As a side note I have tested to just pause the debugger during a call and this also results in bad framerate both for the remote and local track. However worth to note is that even when my local video gets bad framerate it looks good on the other client. This would indicate that something is not working when playing video from a video track locally.
I include my local sdp just in case it is something wrong with that one:
v=0
o=- 3875426963439162405 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0 1
a=msid-semantic: WMS
m=video 52241 UDP/TLS/RTP/SAVPF 96 98
c=IN IP4 ...MY IP ADRESS...
b=AS:1264
a=rtcp:9 IN IP4 0.0.0.0
... SOME ICE CANDIDATES ...
a=ice-ufrag:6ZNW
a=ice-pwd:1JMvi96Ju3YZCX9S+ChJNH2C
a=fingerprint:sha-256 7B:F5:B5:49:E7:76:54:5F:55:D6:D3:2E:97:38:E0:63:63:5F:2E:53:49:BC:BD:B9:1D:40:45:4B:EC:1E:EE:D4
a=setup:actpass
a=mid:0
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:4 urn:3gpp:video-orientation
a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=msid:- SELF_VIDEO
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 x-google-profile-id=0
a=ssrc-group:FID 2190372283 111930078
a=ssrc:2190372283 cname:C+phDL3HvwhlyByD
a=ssrc:2190372283 msid: SELF_VIDEO
a=ssrc:2190372283 mslabel:
a=ssrc:2190372283 label:SELF_VIDEO
a=ssrc:111930078 cname:C+phDL3HvwhlyByD
a=ssrc:111930078 msid: SELF_VIDEO
a=ssrc:111930078 mslabel:
a=ssrc:111930078 label:SELF_VIDEO
m=audio 52242 UDP/TLS/RTP/SAVPF 111 103 104 9 102 0 8 106 105 13 110 112 113 126
c=IN IP4 ...MY IP ADRESS...
a=rtcp:9 IN IP4 0.0.0.0
... SOME ICE CANDIDATES ...
a=ice-ufrag:6ZNW
a=ice-pwd:1JMvi96Ju3YZCX9S+ChJNH2C
a=fingerprint:sha-256 7B:F5:B5:49:E7:76:54:5F:55:D6:D3:2E:97:38:E0:63:63:5F:2E:53:49:BC:BD:B9:1D:40:45:4B:EC:1E:EE:D4
a=setup:actpass
a=mid:1
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=msid:- SELF_AUDIO
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:103 ISAC/16000
a=rtpmap:104 ISAC/32000
a=rtpmap:9 G722/8000
a=rtpmap:102 ILBC/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:106 CN/32000
a=rtpmap:105 CN/16000
a=rtpmap:13 CN/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:112 telephone-event/32000
a=rtpmap:113 telephone-event/16000
a=rtpmap:126 telephone-event/8000
a=ssrc:2339515350 cname:C+phDL3HvwhlyByD
a=ssrc:2339515350 msid: SELF_AUDIO
a=ssrc:2339515350 mslabel:
a=ssrc:2339515350 label:SELF_AUDIO
Any help or suggestions as to what might be wrong would be greatly appreciated!
Are you sure the framerate decreases to 1fps? That is too low. I would advice you to check the exact framerate with different conditions, this can give you some more detailed information about the issue. You can do it for free in Loadero, here are some resources, that will help you create some free tests to get insights:
A blog post with a guide to testing webRTC apps https://blog.loadero.com/2020/08/10/how-to-set-up-an-automated-webrtc-test-with-loadero/
Info about setting network conditions, packet loss, jitter and more https://wiki.loadero.com/test-creation/participant-configuration/network-conditions
How to use post-run assertions, this will allow you get exact FPS https://blog.loadero.com/2020/01/29/how-to-get-the-best-out-of-post-run-assertions/
Sign up here to run those tests and get detailed data https://loadero.com/home
Running tests with different network conditions will help you get detailed info about which network issues cause the FPS decrease and how much of a decrease that is. Hope this will allow you to find the issue in your application.

Simple Webrtc relay bridge Server in C#

I have a fully working peerTopeer (P1, P2) webRTC. To handle peerTopeer failures, I am trying for a simple exchange of bytes via a server in c# between P1 and P2 on a windows machine, as I don't want to develop a turn server by specs. I have also tried to find an open source c# server turn server with turn message but its not working (able to parse request but response seems to be not accepted by latest chrome/MS Edge chromium based)
Simple C# relay bridge server:
With simple udp/tcp listener and exchange of bytes with peers, (P1 to P2 and P2 to P1) and forcing bridge machine IP as candidate I am able to achieve connections and streaming data (bytes) are exchanged.
However unable to see video/hear audio on peers and also after some exchange, the connections are dropped with connectionState failed on the client side.
Q1. It should have worked, what is going wrong?
Q2. Any opensource c# implementation of stun and turn (simple one)?
I appreciate any help in this regard.
Server and Client code samples:
Listen to tcp / udp(not in sample)
public void ListenTCP(int port) {
TcpListener listener = new TcpListener(IPAddress.Any, port);
listener.Start();
while (true){
TcpClient tcpClient = listener.AcceptTcpClient();
..........add endpoint to list
var bytes = readfromtcpstream.......;
Task.Run(() => ProcessData(tcpClient.Client.RemoteEndPoint, bytes));
}
}
ProcessData (exchange stream bytes)
private void Process_DATA(IPEndPoint fromEndPoint, byte[] bytes) {
foreach (var endpoint in list) { //distribute to all other peers
if (endpoint == fromEndPoint) continue;
endpoint's TCPClient.Send(bytes);
}
}
On the client side (Javascript / typescript), forcing the candidate as bridge server
SignalType.Candidate...
candidate = new RTCIceCandidate(Switch the SDP(messageJson.candidate,
BridgeServerAddress, "2525", "tcp"));
m_PeerConnection.addIceCandidate(candidate)
Simply modifying the ice candidate you got from P2P is unlikely to work since TCP candidates work a bit differently. And a TURN server is very different from a simple bridge.
The following SDP contains a TCP candidate with tcptype passive which will make the other side establish a connection to it. Feed it into setRemoteDescription, then create an answer and call setLocalDescription with the answer.
v=0
o=- 2576067654554894849 3 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS
m=audio 9 UDP/TLS/RTP/SAVPF 111
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:2698387310 1 tcp 25042943 127.0.0.1 31337 typ host tcptype passive generation 0
a=ice-ufrag:server
a=ice-pwd:Kv6yCw1HiZ1/6uNExYcE28pO
a=fingerprint:sha-256 22:46:36:8D:B1:CD:08:7B:A1:60:86:BF:95:90:06:4B:EA:47:D9:74:24:FF:6D:2F:1C:09:5B:C1:F5:8D:CC:B2
a=setup:actpass
a=mid:audio
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=recvonly
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
The browser should establish a connection to port 31337 on localhost (note that Firefox doesn't allow localhost ICE by default so try this in Chrome first).
From there, you'll have to process ICE, decrypt SRTP etc.

C# Server to Android Client Behind the NAT

I need to establish a connection from a public ip server implemented in c sharp to an android device behind the NAT and I was able to got SPD message from the android device using ICE4j library using this code
String toSend = SdpUtils.createSDPDescription(agent); //Each computer sends this information
and I got the following message
v=0
o=ice4j.org 0 0 IN IP4 192.168.1.14
s=-
t=0 0
a=ice-options:trickle
a=ice-ufrag:dikj41a5eequb2
a=ice-pwd:3t07qqjndu5pkneh53c6kqti3l
m=audio 5000 RTP/AVP 0
c=IN 192.168.1.14 IP4
a=mid:audio
a=candidate:1 1 udp 2130706431 fe80::1afe:34ff:fe29:c233 5000 typ host
a=candidate:2 1 udp 2130706431 192.168.1.14 5000 typ host
a=candidate:3 1 udp 1677724415 91.93.202.127 5000 typ srflx raddr 192.168.1.14 rport 5000
and the server stores this message so my question is what I have to do to establish a connection from the server to the android device using these information

HTTP Expect Continue performance

In several Internet sources I've seen a general recommendation to disable sending Expect: 100-continue HTTP header in order to increase performance if the client is NOT actually going to send a large body.
However, testing the following code reveals that sending the header makes overall time decrease by ~50ms in average.
var hc = new HttpClient();
hc.DefaultRequestHeaders.ExpectContinue = ?;
hc.BaseAddress = new Uri("http://XXX/api/");
var r = new HttpRequestMessage(HttpMethod.Post, new Uri("YYY", UriKind.Relative))
{
Content = new StringContent("{}", Encoding.UTF8, #"application/json")
};
var tt = hc.SendAsync(r).Result;
tt.Content.ReadAsStringAsync().Result.Dump();
hc.Dispose();
Here is the WireShark dump for request with Expect: 100-continue
1 0.000000000 ss.ss.ss.176 dd.dd.dd.150 TCP 66 54515→80 [SYN] Seq=0 Win=8192 Len=0 MSS=1260 WS=4 SACK_PERM=1
2 0.342137000 dd.dd.dd.150 ss.ss.ss.176 TCP 66 80→54515 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1380 WS=1 SACK_PERM=1
3 0.342687000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54515→80 [ACK] Seq=1 Ack=1 Win=66780 Len=0
4 *REF* ss.ss.ss.176 dd.dd.dd.150 HTTP 272 POST /XXX/api/YYY HTTP/1.1
5 0.361158000 dd.dd.dd.150 ss.ss.ss.176 HTTP 79 HTTP/1.1 100 Continue
6 0.361846000 ss.ss.ss.176 dd.dd.dd.150 TCP 56 54515→80 [PSH, ACK] Seq=219 Ack=26 Win=66752 Len=2
7 0.705497000 dd.dd.dd.150 ss.ss.ss.176 HTTP 461 HTTP/1.1 200 OK (application/json)
8 0.726029000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54515→80 [FIN, ACK] Seq=221 Ack=433 Win=66348 Len=0
9 1.067923000 dd.dd.dd.150 ss.ss.ss.176 TCP 54 80→54515 [FIN, ACK] Seq=433 Ack=222 Win=65535 Len=0
10 1.068466000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54515→80 [ACK] Seq=222 Ack=434 Win=66348 Len=0
The same request without the header:
11 9.300455000 ss.ss.ss.176 dd.dd.dd.150 TCP 66 54516→80 [SYN] Seq=0 Win=8192 Len=0 MSS=1260 WS=4 SACK_PERM=1
12 9.640626000 dd.dd.dd.150 ss.ss.ss.176 TCP 66 80→54516 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1380 WS=1 SACK_PERM=1
13 9.641393000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54516→80 [ACK] Seq=1 Ack=1 Win=66780 Len=0
14 *REF* ss.ss.ss.176 dd.dd.dd.150 HTTP 250 POST /XXX/api/YYY HTTP/1.1
15 0.406794000 dd.dd.dd.150 ss.ss.ss.176 TCP 54 80→54516 [ACK] Seq=1 Ack=197 Win=65535 Len=0
16 0.406963000 ss.ss.ss.176 dd.dd.dd.150 TCP 56 54516→80 [PSH, ACK] Seq=197 Ack=1 Win=66780 Len=2
17 0.749589000 dd.dd.dd.150 ss.ss.ss.176 HTTP 461 HTTP/1.1 200 OK (application/json)
18 0.769053000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54516→80 [FIN, ACK] Seq=199 Ack=408 Win=66372 Len=0
19 1.109276000 dd.dd.dd.150 ss.ss.ss.176 TCP 54 80→54516 [FIN, ACK] Seq=408 Ack=200 Win=65535 Len=0
20 1.109742000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54516→80 [ACK] Seq=200 Ack=409 Win=66372 Len=0
Same results were received for IIS 7.5, IIS 8.0
The questions are:
What makes the request with the Expect header execute faster, when theoretically the opposite shall take place?
Is it always the case that the body of POST request goes within a separate TCP packet (I've looked through only a couple of samples, there this is true)? Here I mean why TCP packet at line 14 in dump does not contain the data (POST body) that was sent in TCP packet at line 16?
I had the same problem (~50 ms of delay). I guess it's a bug on HttpClient implementation of .NET Framework.
I made some test with .NET Core 2.1 and I was able to remove Continue message without performance decay.
Resolved same problem with TcpClient
var tcpClient = new TcpClient();
var uri = new Uri(httpAddress);
tcpClient.Connect(uri.Host, uri.Port);
string httpResponse = null;
using (NetworkStream networkStream = tcpClient.GetStream())
{
var httpRequestBuilder = new StringBuilder();
httpRequestBuilder.AppendLine("POST / HTTP/1.1");
httpRequestBuilder.Append("Host: ").AppendLine(uri.Host);
httpRequestBuilder.AppendLine("Content-Type: application/json");
httpRequestBuilder.Append("Content-Length: ").AppendLine(postJsonBody.Length.ToString());
httpRequestBuilder.AppendLine();
httpRequestBuilder.AppendLine(postJsonBody);
var httpRequest = httpRequestBuilder.ToString();
var requestBytes = Encoding.UTF8.GetBytes(httpRequest);
// sending request as one package
// (without PSH)
networkStream.Write(requestBytes, 0, requestBytes.Length);
// reading response
using (var sr = new StreamReader(networkStream, Encoding.UTF8))
{
httpResponse = sr.ReadToEnd();
}
}
tcpClient.Close();

Categories