From 3ceea07974c3d660eb04f4ae20b28a36ce8f470d Mon Sep 17 00:00:00 2001 From: Simon Shanks Date: Wed, 16 Sep 2026 15:46:45 +0100 Subject: [PATCH] addition of ReceiveTimeout/SendTimeout details added to docs/README.md --- docs/README.md | 25 ++++++++++ kx.Test/Connection/ConnectionTests.cs | 14 ++++++ kx/c.cs | 69 +++++++++++++++++++++------ 3 files changed, 93 insertions(+), 15 deletions(-) diff --git a/docs/README.md b/docs/README.md index c07de0b..531b5f3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -165,6 +165,8 @@ Dict | dictionary | 99 ## Interacting with kdb+ via an open `c` instance +### Synchronous I/O + Interacting with the kdb+ server is very simple. You must make a basic choice between sending a message to the server where you expect no answer, or will check later for an answer. @@ -196,6 +198,29 @@ As a special case of the `k` method, we may receive a message from the server wi public object k() ``` +#### Synchronous I/O send and receive timeouts + +The time allowed for synchronous socket I/O can be configured in milliseconds using `SendTimeout` and `ReceiveTimeout`: + +```c# +using (var connection = new c("localhost", 5000)) +{ + connection.SendTimeout = 5000; + connection.ReceiveTimeout = 10000; + + object result = connection.k("select from trade"); +} +``` + +A value of zero, which is the default, means that no timeout is applied. +These properties configure the underlying socket and apply to synchronous reads and writes performed by methods such as `k`, `ks`, `kn`, and `kr`. +They can be used with TCP and Unix-domain socket connections. + +If a synchronous read or write times out, the stream reports an `IOException`. +The connection is closed before the exception is rethrown because the q IPC message may have been only partially sent or received and the connection can no longer be reused safely. + +The properties are set after construction, so they do not apply to establishing the connection, TLS authentication, or the initial q IPC authentication handshake. + ### Asynchronous I/O The `c` class also provides methods that return `Task` or `Task`. These are an alternative to the `ks` and `k` methods. diff --git a/kx.Test/Connection/ConnectionTests.cs b/kx.Test/Connection/ConnectionTests.cs index 363de65..6a41a5a 100644 --- a/kx.Test/Connection/ConnectionTests.cs +++ b/kx.Test/Connection/ConnectionTests.cs @@ -17,6 +17,20 @@ public void ConnectionInitialises() } } + [Test] + public void ConnectionExposesSynchronousSocketTimeouts() + { + using (var server = new TestableTcpServer()) + using (var connection = new c("localhost", server.TestPort)) + { + connection.SendTimeout = 1000; + connection.ReceiveTimeout = 2000; + + Assert.AreEqual(1000, connection.SendTimeout); + Assert.AreEqual(2000, connection.ReceiveTimeout); + } + } + [Test] public void ConnectionThrowsIfHostIsNull() { diff --git a/kx/c.cs b/kx/c.cs index 6f127eb..76dcefb 100644 --- a/kx/c.cs +++ b/kx/c.cs @@ -495,7 +495,27 @@ protected bool IsLittleEndian public static Encoding e { get; set; } = Encoding.ASCII; /// - /// Requests that the underlying stream and TCP connection be closed. + /// Gets or sets the amount of time, in milliseconds, that a synchronous send operation + /// blocks waiting for completion. A value of zero means no timeout. + /// + public int SendTimeout + { + get { return _socket.SendTimeout; } + set { _socket.SendTimeout = value; } + } + + /// + /// Gets or sets the amount of time, in milliseconds, that a synchronous receive operation + /// blocks waiting for data. A value of zero means no timeout. + /// + public int ReceiveTimeout + { + get { return _socket.ReceiveTimeout; } + set { _socket.ReceiveTimeout = value; } + } + + /// + /// Requests that the underlying stream and connection be closed. /// public void Close() { @@ -503,7 +523,10 @@ public void Close() { _clientStream.Close(); } - _socket.Close(); + if (_socket != null) + { + _socket.Close(); + } } /// @@ -1035,7 +1058,15 @@ protected int ReadInt32() /// The number of bytes to be written to the client stream. protected void Write(byte[] bytes, int number) { - _clientStream.Write(bytes, 0, number); + try + { + _clientStream.Write(bytes, 0, number); + } + catch (IOException) + { + Close(); + throw; + } } /// @@ -1709,7 +1740,7 @@ private void w(object x) private void w(int i, object x) { byte[] buffer = Serialize(i, x); - _clientStream.Write(buffer, 0, buffer.Length); + Write(buffer, buffer.Length); } private bool rb() @@ -2088,23 +2119,31 @@ private async Task wAsync(int i, object x) private void read(byte[] b) { - int k = 0; - int j = b.Length; - while (true) + try { - if (k < j) + int k = 0; + int j = b.Length; + while (true) { - int i; - if ((i = _clientStream.Read(b, k, Math.Min(_maxBufferSize, j - k))) == 0) + if (k < j) { - break; + int i; + if ((i = _clientStream.Read(b, k, Math.Min(_maxBufferSize, j - k))) == 0) + { + break; + } + k += i; + continue; } - k += i; - continue; + return; } - return; + throw new KException("read"); + } + catch (IOException) + { + Close(); + throw; } - throw new KException("read"); } private async Task ReadAsync(byte[] b)