One of the demos that really convinced me of the power of Node was the simple TCP chat server that Ryan Dahl presented in this video: https://www.youtube.com/watch?v=jo_B4LTHi3I&t=28m23s
Here's what the code in the demo looked like:
const net = require('net');
const server = net.createServer();
const sockets = [];
server.on('connection', (socket) => {
sockets.push(socket);
socket.on('data', (message) => {
for (const current_socket of sockets) {
if (current_socket !== socket) {
current_socket.write(message);
}
}
});
socket.on('end', () => {
const index = sockets.indexOf(socket);
sockets.splice(index, 1);
});
});
server.listen(8000, () => console.log('tcp server listening on port 8000'));
The only TCP example I found on the Deno website is an echo server that looks like this:
const listener = Deno.listen({ port: 8080 });
console.log("listening on 0.0.0.0:8080");
for await (const conn of listener) {
Deno.copy(conn, conn);
}
It's nice and compact, but I haven't been able to use Deno.Conn
's read
and write
methods to turn this example into a TCP chat server. Any help would be much appreciated! I also think it would be a useful example to add to the website.
Use Deno.listen
to create the server and Deno.connect
to connect to that server.
A simple example of tcp
server/client would be:
server.js
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const listener = Deno.listen({ port: 8080 });
console.log("listening on 0.0.0.0:8080");
for await (const conn of listener) {
// Read message
const buf = new Uint8Array(1024);
await conn.read(buf);
console.log('Server - received:', decoder.decode(buf))
// Respond
await conn.write(encoder.encode('pong'))
conn.close();
}
client.js
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const conn = await Deno.connect({ hostname: "127.0.0.1", port: 8080 })
// Write to the server
await conn.write(encoder.encode('ping'));
// Read response
const buf = new Uint8Array(1024);
await conn.read(buf);
console.log('Client - Response:', decoder.decode(buf))
conn.close();
You can build from here. For a chat server, you'll keep the connection open, and send multiple messages for example.
Alright, after more playing around, here's my TCP chat server:
const server = Deno.listen({ port: 8000 });
console.log("tcp server listening on port 8000");
const connections: Deno.Conn[] = [];
for await (const connection of server) {
// new connection
connections.push(connection);
handle_connection(connection);
}
async function handle_connection(connection: Deno.Conn) {
let buffer = new Uint8Array(1024);
while (true) {
const count = await connection.read(buffer);
if (!count) {
// connection closed
const index = connections.indexOf(connection);
connections.splice(index, 1);
break;
} else {
// message received
let message = buffer.subarray(0, count);
for (const current_connection of connections) {
if (current_connection !== connection) {
await current_connection.write(message);
}
}
}
}
}
The code looks quite different from the Node version. That said, TCP does not maintain message boundaries and the Deno version makes that explicit by reading into a Uint8Array
buffer. That's similar to how Rust's std::net
and tokio::net
modules handle TCP. Actually, I'm not too sure what the socket.on('data')
events represent in Node; it seems like just an arbitrary-length piece of data from the TCP stream.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With