{
"title": "tcpserver",
"category": "io/net",
"keywords": [
"tcpserver",
"tcp",
"socket",
"networking",
"server",
"loopback"
],
"summary": "Create a TCP server that listens for MATLAB-compatible client connections.",
"references": [
"https://www.mathworks.com/help/matlab/ref/tcpserver.html"
],
"gpu_support": {
"elementwise": false,
"reduction": false,
"precisions": [],
"broadcasting": "none",
"notes": "TCP sockets run on the host CPU. GPU-resident inputs are gathered automatically before binding sockets."
},
"fusion": {
"elementwise": false,
"reduction": false,
"max_inputs": 1,
"constants": "inline"
},
"requires_feature": null,
"tested": {
"unit": "builtins::io::net::tcpserver::tests",
"integration": "builtins::io::net::tcpserver::tests::tcpserver_accepts_loopback_connection"
},
"description": "`tcpserver(address, port)` creates a TCP/IP listener that waits for clients and exposes MATLAB-compatible properties describing the socket. RunMat mirrors this behaviour: addresses may be IPv4, IPv6, or hostnames, and the function returns a handle-like struct whose fields match MATLAB’s `tcpserver` object (including `ServerAddress`, `ServerPort`, `Timeout`, `UserData`, and `BytesAvailableFcn` metadata). The builtin validates inputs, binds the socket, records configuration, and raises MATLAB-style diagnostics on failure.",
"behaviors": [
"`tcpserver(address, port)` binds to the requested interface; pass `\"0.0.0.0\"` or `\"::\"` to listen on every IPv4 or IPv6 adapter respectively.",
"Ports must be in the range `0–65535`. Passing `0` requests an ephemeral OS-assigned port that RunMat reports in the returned struct.",
"Supported name-value pairs mirror MATLAB defaults: `Timeout` (non-negative seconds, default `10`), `UserData` (stored verbatim), `Name` (defaults to `\"tcpserver:<address>:<port>\"`), and `ByteOrder` (`\"little-endian\"` or `\"big-endian\"`). Unsupported options raise `RunMat:tcpserver:InvalidNameValue`.",
"The returned struct mirrors MATLAB properties, including connection state, callback metadata, and an internal `__tcpserver_id` identifier that future networking builtins use to locate the listener.",
"GPU-resident scalars are gathered automatically before binding so that socket setup always executes on the host CPU.",
"Bind failures raise `RunMat:tcpserver:BindFailed` with the OS-provided error message, preserving MATLAB-style diagnostics."
],
"examples": [
{
"description": "Creating a loopback TCP server on a fixed port",
"input": "srv = tcpserver(\"127.0.0.1\", 55000);\ndisp(srv.ServerAddress)\ndisp(srv.ServerPort)",
"output": "127.0.0.1\n55000"
},
{
"description": "Requesting an ephemeral port and inspecting the assigned value",
"input": "srv = tcpserver(\"0.0.0.0\", 0);\nfprintf(\"Listening on %s:%d\\n\", srv.ServerAddress, srv.ServerPort)",
"output": "Listening on 0.0.0.0:54873 % actual port varies by run"
},
{
"description": "Configuring the timeout and storing metadata in UserData",
"input": "srv = tcpserver(\"localhost\", 60000, \"Timeout\", 5, \"UserData\", struct(\"name\", \"demo\"));\ndisp(srv.Timeout)\ndisp(srv.UserData.name)",
"output": "5\ndemo"
},
{
"description": "Assigning a custom server name",
"input": "srv = tcpserver(\"::1\", 45000, \"Name\", \"LoopbackServer\");\ndisp(srv.Name)",
"output": "LoopbackServer"
},
{
"description": "Selecting big-endian byte order for binary protocols",
"input": "srv = tcpserver(\"127.0.0.1\", 45001, \"ByteOrder\", \"big-endian\");\ndisp(srv.ByteOrder)",
"output": "big-endian"
},
{
"description": "Handling invalid ports with MATLAB-style diagnostics",
"input": "try\n srv = tcpserver(\"127.0.0.1\", 99999);\ncatch err\n disp(err.identifier)\n disp(err.message)\nend",
"output": "RunMat:tcpserver:InvalidPort\nRunMat:tcpserver:InvalidPort: tcpserver: port 99999 is outside the valid range 0–65535"
}
],
"faqs": [
{
"question": "What range of ports can I use?",
"answer": "Valid ports are `0–65535`. Port `0` lets the OS choose an available ephemeral port, which RunMat reports in the returned struct."
},
{
"question": "How do I discover which clients are connected?",
"answer": "The returned struct exposes MATLAB-compatible fields (`Connected`, `ClientAddress`, `ClientPort`). Future networking builtins will use the internal `__tcpserver_id` to inspect active connections."
},
{
"question": "Does RunMat support IPv6?",
"answer": "Yes. Pass an IPv6 literal (e.g., `\"::1\"`) or hostname that resolves to IPv6. The returned `ServerAddress` reflects the bound address."
},
{
"question": "Can I change the timeout after creating the server?",
"answer": "Not yet. The current builtin records the timeout value for future builtins. A forthcoming setter will update the listener configuration."
},
{
"question": "Does `tcpserver` fire callbacks like MATLAB’s `BytesAvailableFcn`?",
"answer": "Callback-related properties are present for compatibility, and future updates will allow callers to configure them. They currently act as placeholders while connection management matures."
},
{
"question": "How do I close the server?",
"answer": "A companion builtin (planned) will accept the returned struct and release the underlying listener. Tests can invoke internal helpers until that builtin lands."
},
{
"question": "Can I use GPU arrays for address or port?",
"answer": "Yes—RunMat gathers them automatically before binding."
},
{
"question": "What happens if the port is already in use?",
"answer": "`tcpserver` raises `RunMat:tcpserver:BindFailed` with the OS error message."
},
{
"question": "How do I pass additional socket options?",
"answer": "Current support covers `Timeout`, `Name`, `UserData`, and `ByteOrder`. Additional name-value options (broadcast, reuse, keep-alive) will land alongside their corresponding provider hooks."
},
{
"question": "Is TLS supported?",
"answer": "Not directly. Combine `tcpserver` with application-layer protocol helpers or custom TLS wrappers until dedicated support lands."
}
],
"links": [
{
"label": "fopen",
"url": "./fopen"
},
{
"label": "fread",
"url": "./fread"
},
{
"label": "fwrite",
"url": "./fwrite"
},
{
"label": "fprintf",
"url": "./fprintf"
},
{
"label": "accept",
"url": "./accept"
},
{
"label": "close",
"url": "./close"
},
{
"label": "read",
"url": "./read"
},
{
"label": "readline",
"url": "./readline"
},
{
"label": "tcpclient",
"url": "./tcpclient"
},
{
"label": "write",
"url": "./write"
}
],
"source": {
"label": "crates/runmat-runtime/src/builtins/io/net/tcpserver.rs",
"url": "crates/runmat-runtime/src/builtins/io/net/tcpserver.rs"
},
"gpu_residency": "No. `tcpserver` is a host-side operation. RunMat transparently gathers GPU scalars before binding the socket, so keeping address or port values on the GPU provides no performance benefit.",
"gpu_behavior": [
"Networking occurs entirely on the host CPU. If the address or port arguments originate on the GPU, RunMat gathers them before binding the socket. The struct returned by `tcpserver` is always CPU-resident, and acceleration providers do not need to implement any hooks for this builtin."
]
}