Chilkat.Socket fundamentals

Build the protocol on top of the byte stream

Reliable socket code begins with one fact: a connected Chilkat.Socket presents an ordered byte stream, not a sequence of application messages. The same application-facing stream is used whether the connection is plain, protected by TLS, or carried through an SSH tunnel. Chilkat handles the TLS or SSH protocol details internally; your application reads and writes ordinary bytes. It must still define message boundaries, choose receive methods that match those boundaries, use explicit timeouts, and handle partial I/O correctly.

1 Define message framing Choose fixed length, length prefix, delimiter, or connection close.
2 Choose the receive contract One delivery, exactly N bytes, or read through a delimiter.
3 Set finite idle timeouts Avoid waiting forever when a peer stops making progress.
4 Check results immediately Failure reasons and result properties can later become stale.
5 Make encoding and TLS explicit Bytes, text encoding, certificate trust, and SNI are separate concerns.

1. A byte stream does not preserve messages

A successful send places bytes into the connected byte stream. The receiver may obtain those bytes in different-sized pieces, and the boundaries between send calls are not preserved. This application-level behavior is the same for a plain connection, TLS, or a connection carried through an SSH tunnel.

One application interface over different connection types. Your code uses the same SendXxx and ReceiveXxx methods for a plain socket, TLS, or a connection opened through an SSH tunnel. Chilkat performs encryption, decryption, TLS record processing, and SSH packet handling internally. Those protocol details do not change the application's framing rules: the application still sees one ordered byte stream.
Byte stream and receive boundaries Two application messages are written to the byte stream, but three receive calls return different chunks that do not match the original message boundaries. Sender calls Message A Message B Connected byte stream more bytes may follow Receiver calls Receive #1 part of A Receive #2 rest of A + part of B Receive #3 rest of B Send boundaries and receive boundaries are independent.

One send can require several receives, and one receive can contain bytes from several sends.

ReceivePacketSize is not a message-size setting. For a plain TCP connection it limits the amount requested by one underlying availability-based read. It does not create or preserve application message boundaries. TLS and SSH receive sizes are governed by their own record or packet processing, and already-buffered data may exceed ReceivePacketSize.

2. Every protocol needs a framing rule

The receiver must know when a complete application message has arrived. Without a framing rule, it cannot distinguish “the message is complete” from “more bytes have not arrived yet.”

Fixed length

Every message or field has a predetermined byte count. This is simple and efficient when the protocol truly uses fixed-size records.

Use exact-length methods such as ReceiveBytesN or ReceiveBdN.

Length prefix

Send a fixed-size integer first, followed by that many payload bytes. Both sides must agree on integer width, signedness, and byte order.

Chilkat provides SendCount, ReceiveCount, and explicit 16-bit and 32-bit integer methods.

Delimiter

End a message with an agreed byte sequence such as CRLF, a line-feed, or a protocol-specific marker.

Use ReceiveUntilMatch, ReceiveToCRLF, or a byte-delimiter receive method.

Length-prefixed message

Length-prefixed application message A four-byte length field with the value 12 is followed by a twelve-byte payload. Wire format 4-byte length 00 00 00 0C 12-byte payload application data 1. Read and validate the length ReceiveCount() → 12 2. Read exactly that many bytes ReceiveBytesN(12)
Never trust a peer-supplied length without validation. Reject negative values, values above the protocol maximum, and values that would cause unreasonable memory allocation. ReceiveCount returns a signed 32-bit value and reserves -1 as its failure result. Its byte order is controlled by BigEndian, which defaults to network byte order.

Delimiter-based message

Delimiter matching is byte-oriented. For ReceiveUntilMatch, Chilkat encodes the match string using StringCharset and performs an exact, case-sensitive byte comparison. A match may span several underlying network reads.

Method Delimiter Returned data Important behavior
ReceiveUntilMatch matchStr encoded with StringCharset Text through and including the match Exact, case-sensitive byte match; partial content is discarded on failure.
ReceiveUntilMatchSb Same as above Appends text through and including the match The destination is unchanged on failure, but consumed bytes are not recoverable.
ReceiveToCRLF CR+LF encoded with StringCharset Text including the line terminator Usually matches 0D 0A with ASCII-compatible encodings.
ReceiveUntilByteBd One raw byte Appends bytes including the delimiter Partial bytes remain in the BinData destination on failure.
ReceiveStringUntilByte One raw byte Text preceding the delimiter A non-ASCII delimiter can split a multibyte encoded character.

3. Choose the receive method by its contract

Chilkat offers several receive families because they solve different protocol problems. Choosing by data type alone is not enough; choose by completion rule.

Receive contract Representative methods When the call completes Failure considerations
One available delivery ReceiveBytes
ReceiveBd
ReceiveString
ReceiveSb
Returns internally buffered data first; otherwise performs one receive operation. It does not drain the entire connection. An orderly close is reported as failure, but final bytes received with the close can still be present in the output.
Exactly N bytes ReceiveBytesN
ReceiveBdN
ReceiveNBytesENC
Continues until the requested count is satisfied or a receive failure occurs. Partial-output behavior differs by method. Read the specific method description before deciding whether a failed call's destination is usable.
Through a delimiter ReceiveUntilMatch
ReceiveUntilByteBd
ReceiveToCRLF
Continues until the configured delimiter is found. Some methods retain partial data on failure; others discard it. Delimiter inclusion also varies.
Fixed-size integer ReceiveByte
ReceiveInt16
ReceiveInt32
ReceiveCount
Requires the complete 1-, 2-, or 4-byte value. A failed partial integer read consumes and discards the bytes already read, which can leave the protocol stream misaligned.
Failure does not always mean “no data.” A receive can consume bytes before it fails. Depending on the method, those bytes may be returned, appended to a destination, or discarded. They remain included in ReceivedCount. Always check the specific receive method's failure contract.

Integer receive results

ReceiveByte, ReceiveInt16, and ReceiveInt32 place a successful result in ReceivedInt. A failed call does not clear that property; it retains the value from the last successful integer receive.

success = socket.ReceiveInt32(true)

if success:
    value = socket.ReceivedInt
else:
    reason = socket.ReceiveFailReason
    # Do not use ReceivedInt here; it may be stale.

4. Sending, buffering, and backpressure

A synchronous Chilkat send method encodes or accepts the application's data and attempts to move the resulting bytes through the connection. Chilkat and the operating system may buffer outgoing data, so early sends can complete quickly. If the application produces data faster than the connection or peer can accept it, the send eventually waits for additional progress. This is called backpressure. For TLS and SSH connections, Chilkat handles the security-protocol framing internally.

Send buffering and backpressure Application data moves through connection buffering and then to the peer. When no additional bytes can move, the application send waits for progress. Application SendBytes / SendString Connection buffering finite capacity Peer reads at its own rate copy/write network progress When no bytes can move, MaxSendIdleMs limits the stall.
A failed send may already be partial. A false result from SendBytes, SendBd, or SendString does not prove that zero bytes reached the peer. Chilkat does not retain the unsent remainder and does not report how many bytes were transmitted. For a length-prefixed, delimited, or otherwise framed protocol, the safest recovery is usually to close the connection and start a new session.

SendString adds no length prefix or terminator. It only encodes the string using StringCharset and sends the resulting bytes. Any message framing must be added by the application.

5. Understand the different timeout scopes

Socket timeouts are not all interchangeable. The timeout argument passed to Connect governs connection establishment, while MaxReadIdleMs and MaxSendIdleMs govern periods with no I/O progress.

Phase or operation Primary control Meaning
DNS lookup and connection establishment Connect(..., maxWaitMs) An overall connection-establishment budget. A value of 0 means wait indefinitely, subject to an internal practical ceiling.
Receive methods MaxReadIdleMs Maximum continuous period with no received byte. The timer resets whenever read progress occurs.
Send methods MaxSendIdleMs Maximum continuous period with no sent byte. The timer resets whenever write progress occurs.
TLS handshake MaxReadIdleMs and MaxSendIdleMs The TLS handshake exchanges protocol data after the underlying network connection is established. Chilkat handles this exchange internally.
HTTP/SOCKS proxy negotiation Read/write idle timeouts No separate proxy-negotiation timeout property is provided.
Idle timeout is not total duration. A transfer can run much longer than MaxReadIdleMs or MaxSendIdleMs as long as bytes continue to move. A value of 0 disables the corresponding idle timeout and permits an indefinite wait. Use finite values for externally controlled peers.

6. Treat return values as authoritative

A Boolean return value should be checked before inspecting result properties. Capture any matching failure reason immediately after the operation.

Property What it describes Why immediate capture matters
ConnectFailReason The most recent connect-family operation It can retain an older reason until another connect begins.
AcceptFailReason The most recent accept operation Unrelated operations do not clear it.
ReceiveFailReason The most recent receive-side operation It can remain set while sends and other methods are called.
SendFailReason The most recent send-side operation It can remain set until the next send begins.
LastMethodFailed The most recent action method A later helper or certificate method can overwrite it.
ReceivedInt The last successful integer receive A failed integer receive leaves the previous value unchanged.

IsConnected is also a last-known state, not a guarantee. An idle application is not continuously notified that a peer or network path has vanished. The property may remain true until a read, write, or other socket operation detects the loss.

success = socket.SendBytes(data)

if not success:
    reason = socket.SendFailReason
    errorText = socket.LastErrorText
    # Capture these before calling another action method.

7. The byte stream carries bytes, not characters

Text-oriented methods use StringCharset to convert between application strings and wire bytes. Both peers must agree on the same encoding.

Text encoding across a socket A sender encodes text to bytes, the socket transports those bytes, and the receiver decodes them using the same character encoding. TLS or SSH protection, when used, is handled below this application-facing byte stream. Application text "café" StringCharset = utf-8 Socket byte stream 63 61 66 C3 A9 no character information is carried Decoded text "café" must also decode as UTF-8 encode decode Different encodings can produce different byte counts and delimiter sequences.
Prefer an explicit encoding such as utf-8. The default value ansi means the system default encoding determined by the default system locale. It is not a fixed encoding such as Windows-1252, ISO-8859-1, or ASCII, and it can differ between computers.

Use byte-oriented methods for binary protocols or whenever exact byte preservation matters. Also remember that delimiter methods compare encoded bytes. For example, ReceiveToCRLF searches for CR+LF encoded with StringCharset; with UTF-8 that is 0D 0A, while a UTF-16 encoding produces a wider byte sequence.

8. Secure the connection deliberately

TLS adds confidentiality and peer authentication, but the relevant checks are controlled separately.

Setting Purpose Practical guidance
RequireSslCertVerify Validates certificate dates, signatures, and trusted certificate chain. The default is false. Enable it for a normal TLS client unless a controlled environment intentionally uses a different trust model.
SniHostname Sets the SNI name sent in the TLS ClientHello. Usually the hostname passed to Connect is used. Set this when connecting to an IP address or alternate endpoint for a named virtual host.
TlsPinSet Requires the server public key to match one of the configured SPKI pins. Pinning is enforced independently of normal chain verification. Plan for server key rotation by configuring backup pins in advance.
SslProtocol Limits allowed TLS protocol versions. Prefer default or a minimum such as TLS 1.2 or higher. Avoid SSL 3.0, TLS 1.0, and TLS 1.1.
SslAllowedCiphers Restricts allowed cipher suites or selects a policy keyword. Leave empty unless interoperability or policy requires a restriction. best-practices applies Chilkat's current policy.
TLS result properties can describe an earlier handshake. TlsVersion and TlsCipherSuite are retained from the most recent successful TLS handshake. They are not cleared by Close, a failed connection, a later non-TLS connection, or ConvertFromSsl. Do not use them alone to decide whether the current connection is protected by TLS.

9. Multiple connections: socket sets

A socket set allows one Socket object to own multiple listener and/or connected sockets and wait for readiness across the group. It is useful for servers, multiplexed clients, and event-loop designs that should not block on one connection while another is ready.

n = socketSet.SelectForReading(timeoutMs)

for i = 0 to n - 1:
    socketSet.SelectorReadIndex = i

    # Operations now route to the i-th read-ready socket.
    # Call AcceptNext for a listener or ReceiveXxx for a connection.
Do not translate a ready index into SelectorIndex. SelectorReadIndex, SelectorWriteIndex, and SelectorIndex are mutually exclusive. Assign the read-ready or write-ready position directly to the corresponding ready selector.

See the Socket Sets Overview for the complete ownership, selection, readiness, removal, and index-lifetime rules.

10. A practical implementation checklist

Write down the wire format before writing socket code.
Define integer width, byte order, and allowed length range.
Use exact-length receives only when the protocol supplies an exact length.
Use delimiter receives only when the delimiter cannot be ambiguous in the payload.
Set finite MaxReadIdleMs and MaxSendIdleMs.
Check every action method's return value immediately.
Capture the matching failure reason before another method call.
Assume a failed send may have transmitted a partial message.
Validate all peer-supplied sizes before allocation or receive.
Use an explicit text encoding, preferably UTF-8.
Enable certificate verification for normal TLS clients.
Do not treat IsConnected as a guarantee of future success.