Skip to content

Commit c75c8a0

Browse files
mregensxleixer
andauthored
By default set NoDelay and Lingerstate to 5 sec (#3000)
Set NoDelay=true to disable the Nagle algorithm and set Lingerstate to 5 seconds by default. After careful evaluation of the PR provided by @sxleixer in #2882 we found that the default setting of the socket with NoDelay=false can not only cause issues on the client side, but also on the server side. Due to the nature of Nagle's implementation the issue only occurs when many small service requests or responses are sent over the network. In that case, when packets are still in flight, the secondary small packets are delayed and combined until the MTU is exceeded or the previous packages are acknoledged. The expectation in the UA protocol is to not add additional latency in the client-server communication. As a conclusion defaulting to NoDelay=true appears to be the better default option which works for all use cases. If there are new bandwidth issues related to more and larger packets imposed by this change, they should be solved at the UA application level by combining service requests of the same type. Setting Lingerstate to 5 seconds should help to finish communications when sockets are closed. Co-authored-by: @sxleixer <[email protected]>
1 parent 37cebe3 commit c75c8a0

File tree

2 files changed

+20
-41
lines changed

2 files changed

+20
-41
lines changed

Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageSocket.cs

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -667,38 +667,18 @@ private bool ReadNext()
667667
/// </summary>
668668
private delegate void CallbackAction(SocketError error);
669669

670-
/// <summary>
671-
/// Try to connect to endpoint and do callback if connected successfully
672-
/// </summary>
673-
/// <param name="address">Endpoint address</param>
674-
/// <param name="addressFamily">Endpoint address family</param>
675-
/// <param name="port">Endpoint port</param>
676-
/// <param name="callback">Callback that must be executed if the connection would be established</param>
677-
private SocketError BeginConnect(IPAddress address, AddressFamily addressFamily, int port, CallbackAction callback)
678-
{
679-
var socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
680-
var args = new SocketAsyncEventArgs() {
681-
UserToken = callback,
682-
RemoteEndPoint = new IPEndPoint(address, port),
683-
};
684-
args.Completed += OnSocketConnected;
685-
if (!socket.ConnectAsync(args))
686-
{
687-
// I/O completed synchronously
688-
OnSocketConnected(socket, args);
689-
return args.SocketError;
690-
}
691-
return SocketError.InProgress;
692-
}
693-
694670
/// <summary>
695671
/// Try to connect to endpoint and do callback if connected successfully
696672
/// </summary>
697673
/// <param name="endpoint">The DNS endpoint</param>
698674
/// <param name="callback">Callback that must be executed if the connection would be established</param>
699675
private SocketError BeginConnect(DnsEndPoint endpoint, CallbackAction callback)
700676
{
701-
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
677+
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp){
678+
NoDelay = true,
679+
LingerState = new LingerOption(true, 5),
680+
};
681+
702682
var args = new SocketAsyncEventArgs() {
703683
UserToken = callback,
704684
RemoteEndPoint = endpoint,

Stack/Opc.Ua.Core/Stack/Tcp/TcpTransportListener.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -577,24 +577,18 @@ public void Start()
577577
port = Utils.UaTcpDefaultPort;
578578
}
579579

580-
bool bindToSpecifiedAddress = true;
581580
UriHostNameType hostType = Uri.CheckHostName(m_uri.Host);
582-
if (hostType == UriHostNameType.Dns || hostType == UriHostNameType.Unknown || hostType == UriHostNameType.Basic)
583-
{
584-
bindToSpecifiedAddress = false;
585-
}
586-
587-
IPAddress ipAddress = IPAddress.Any;
588-
if (bindToSpecifiedAddress)
589-
{
590-
ipAddress = IPAddress.Parse(m_uri.Host);
591-
}
581+
bool bindToSpecifiedAddress = hostType != UriHostNameType.Dns && hostType != UriHostNameType.Unknown && hostType != UriHostNameType.Basic;
582+
IPAddress ipAddress = bindToSpecifiedAddress ? IPAddress.Parse(m_uri.Host) : IPAddress.Any;
592583

593584
// create IPv4 or IPv6 socket.
594585
try
595586
{
596587
IPEndPoint endpoint = new IPEndPoint(ipAddress, port);
597-
m_listeningSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
588+
m_listeningSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) {
589+
NoDelay = true,
590+
LingerState = new LingerOption(true, 5),
591+
};
598592
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
599593
args.Completed += OnAccept;
600594
args.UserToken = m_listeningSocket;
@@ -628,12 +622,17 @@ public void Start()
628622
try
629623
{
630624
IPEndPoint endpointIPv6 = new IPEndPoint(IPAddress.IPv6Any, port);
631-
m_listeningSocketIPv6 = new Socket(endpointIPv6.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
632-
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
625+
m_listeningSocketIPv6 = new Socket(endpointIPv6.AddressFamily, SocketType.Stream, ProtocolType.Tcp) {
626+
NoDelay = true,
627+
LingerState = new LingerOption(true, 5),
628+
};
629+
SocketAsyncEventArgs args = new SocketAsyncEventArgs() {
630+
UserToken = m_listeningSocketIPv6
631+
};
633632
args.Completed += OnAccept;
634-
args.UserToken = m_listeningSocketIPv6;
633+
635634
m_listeningSocketIPv6.Bind(endpointIPv6);
636-
m_listeningSocketIPv6.Listen(Int32.MaxValue);
635+
m_listeningSocketIPv6.Listen(kSocketBacklog);
637636
if (!m_listeningSocketIPv6.AcceptAsync(args))
638637
{
639638
OnAccept(null, args);

0 commit comments

Comments
 (0)