Deno’s network programming capabilities are built on modern web standards, offering a comprehensive toolchain from low-level sockets to high-level HTTP services. Compared to Node.js, Deno’s network APIs are more modern, emphasizing security and consistency. This tutorial deeply explores Deno’s core network programming techniques, showcasing applications from basic to advanced through code examples.
Basic Network Programming
TCP/UDP Communication Basics
TCP Server Implementation
// tcp_server.ts
const listener = Deno.listen({ port: 8000 });
console.log("TCP server listening on 0.0.0.0:8000");
for await (const conn of listener) {
handleConnection(conn);
}
async function handleConnection(conn: Deno.Conn) {
try {
const buffer = new Uint8Array(1024);
const bytesRead = await conn.read(buffer);
if (bytesRead === null) return;
const message = new TextDecoder().decode(buffer.subarray(0, bytesRead));
console.log("Received:", message);
const response = `Echo: ${message}`;
await conn.write(new TextEncoder().encode(response));
} catch (error) {
console.error("Connection error:", error);
} finally {
conn.close();
}
}
// Run: deno run --allow-net tcp_server.tsTCP Client Implementation
// tcp_client.ts
const conn = await Deno.connect({ hostname: "127.0.0.1", port: 8000 });
try {
const message = "Hello Deno!";
await conn.write(new TextEncoder().encode(message));
const buffer = new Uint8Array(1024);
const bytesRead = await conn.read(buffer);
if (bytesRead !== null) {
const response = new TextDecoder().decode(buffer.subarray(0, bytesRead));
console.log("Server response:", response);
}
} finally {
conn.close();
}
// Run: deno run --allow-net tcp_client.tsUDP Communication Example
UDP Server
// udp_server.ts
const socket = Deno.listenDatagram({ port: 3000, transport: "udp" });
console.log("UDP server listening on 0.0.0.0:3000");
for await (const event of socket) {
if (event.kind === "message") {
const [data, remoteAddr] = event;
console.log(`Received from ${remoteAddr.hostname}:${remoteAddr.port}:`,
new TextDecoder().decode(data));
// Echo message
await socket.send(data, remoteAddr);
}
}
// Run: deno run --allow-net udp_server.tsUDP Client
// udp_client.ts
const socket = Deno.listenDatagram({ port: 0, transport: "udp" }); // Random port
const serverAddr = { hostname: "127.0.0.1", port: 3000 };
const message = new TextEncoder().encode("Hello UDP!");
await socket.send(message, serverAddr);
const [response] = await socket.receive();
console.log("Server response:", new TextDecoder().decode(response));
socket.close();
// Run: deno run --allow-net udp_client.tsHTTP Protocol Implementation
HTTP Server Development
Basic HTTP Server
// http_server.ts
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serve({ port: 8000 });
console.log("HTTP server running on http://localhost:8000");
for await (const req of server) {
// Set response headers
const headers = new Headers();
headers.set("Content-Type", "text/plain");
headers.set("X-Custom-Header", "Deno");
// Build response
req.respond({
status: 200,
headers,
body: "Hello from Deno HTTP server!\n"
});
}
// Run: deno run --allow-net http_server.tsRouting Implementation
// http_router.ts
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serve({ port: 8000 });
interface RouteHandler {
(req: Request, params: Record<string, string>): Promise<Response>;
}
const routes: Record<string, RouteHandler> = {
"/": handleRoot,
"/hello": handleHello,
"/user/:id": handleUser
};
async function handleRequest(req: Request): Promise<Response> {
const url = new URL(req.url);
const path = url.pathname;
const method = req.method;
// Simple route matching
for (const [route, handler] of Object.entries(routes)) {
const match = path.match(routeToRegex(route));
if (match) {
const params = extractParams(route, match);
return handler(req, params);
}
}
return new Response("404 Not Found", { status: 404 });
}
function routeToRegex(route: string): RegExp {
return new RegExp("^" + route.replace(/:\w+/g, "([^/]+)") + "$");
}
function extractParams(route: string, match: RegExpMatchArray): Record<string, string> {
const params: Record<string, string> = {};
const paramNames = route.match(/:\w+/g) || [];
paramNames.forEach((name, i) => {
params[name.substring(1)] = match[i + 1];
});
return params;
}
async function handleRoot(req: Request, _params: Record<string, string>): Promise<Response> {
return new Response("Welcome to Deno HTTP Server!\n");
}
async function handleHello(req: Request, _params: Record<string, string>): Promise<Response> {
return new Response("Hello World!\n");
}
async function handleUser(req: Request, params: Record<string, string>): Promise<Response> {
return new Response(`User ID: ${params.id}\n`);
}
for await (const req of server) {
req.respond(await handleRequest(req));
}
// Run: deno run --allow-net http_router.tsAdvanced HTTP Client Usage
Request with Timeout
// http_client_timeout.ts
async function fetchWithTimeout(
url: string,
options: RequestInit & { timeout?: number } = {}
): Promise<Response> {
const { timeout = 5000, ...fetchOptions } = options;
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...fetchOptions,
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof DOMException && error.name === "AbortError") {
throw new Error(`Request timed out after ${timeout}ms`);
}
throw error;
}
}
// Usage example
try {
const response = await fetchWithTimeout("https://httpbin.org/delay/3", {
timeout: 2000
});
console.log(await response.text());
} catch (error) {
console.error("Request failed:", error.message);
}
// Run: deno run --allow-net http_client_timeout.tsFile Upload Implementation
// http_file_upload.ts
async function uploadFile(
url: string,
filePath: string,
fieldName: string = "file"
): Promise<Response> {
const file = await Deno.open(filePath, { read: true });
const fileStat = await Deno.stat(filePath);
// Build FormData
const formData = new FormData();
formData.append(fieldName, file.readable);
// Create request
const request = new Request(url, {
method: "POST",
body: formData,
headers: {
"Content-Type": `multipart/form-data; boundary=${formData.boundary}`
}
});
const response = await fetch(request);
file.close();
return response;
}
// Usage example
const response = await uploadFile(
"https://httpbin.org/post",
"./example.txt"
);
console.log(await response.json());
// Run: deno run --allow-read --allow-net http_file_upload.tsWebSocket Communication
WebSocket Server
Basic WebSocket Server
// websocket_server.ts
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serve({ port: 8080 });
console.log("WebSocket server running on ws://localhost:8080");
for await (const req of server) {
if (req.headers.get("upgrade")?.toLowerCase() !== "websocket") {
req.respond({ status: 400, body: "Not a WebSocket request\n" });
continue;
}
// Upgrade WebSocket connection
const { socket, response } = Deno.upgradeWebSocket(req);
// WebSocket event handling
socket.onopen = () => {
console.log("Client connected");
socket.send("Welcome to Deno WebSocket server!");
};
socket.onmessage = (e) => {
console.log("Received message:", e.data);
socket.send(`Echo: ${e.data}`);
};
socket.onclose = () => console.log("Client disconnected");
socket.onerror = (e) => console.error("WebSocket error:", e);
req.respondWith(response);
}
// Run: deno run --allow-net websocket_server.tsWebSocket Client
Basic WebSocket Client
// websocket_client.ts
const socket = new WebSocket("ws://localhost:8080");
socket.onopen = () => {
console.log("Connected to server");
socket.send("Hello from client!");
};
socket.onmessage = (e) => {
console.log("Server message:", e.data);
};
socket.onclose = () => console.log("Disconnected from server");
socket.onerror = (e) => console.error("WebSocket error:", e);
// Run: deno run --allow-net websocket_client.tsAdvanced Network Programming
HTTP/2 Implementation
HTTP/2 Server
// http2_server.ts
import { serveTls } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serveTls({
port: 443,
certFile: "./cert.pem",
keyFile: "./key.pem",
});
console.log("HTTP/2 server running on https://localhost:443");
for await (const req of server) {
req.respond({
status: 200,
headers: new Headers({ "Content-Type": "text/plain" }),
body: "Hello from HTTP/2 server!\n"
});
}
// Note: Requires valid TLS certificate
// Run: deno run --allow-net --allow-read http2_server.tsProxy Server Implementation
HTTP Proxy Server
// proxy_server.ts
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serve({ port: 8080 });
console.log("HTTP proxy server running on http://localhost:8080");
for await (const req of server) {
// Handle CONNECT method (HTTPS proxy)
if (req.method === "CONNECT") {
handleConnectProxy(req);
} else {
handleHttpProxy(req);
}
}
async function handleConnectProxy(req: Request) {
const url = new URL(req.url);
const [hostname, portStr] = url.hostname.split(":");
const port = portStr ? parseInt(portStr) : 443;
// Establish TCP connection to target server
const tcpConn = await Deno.connect({ hostname, port });
// Inform client connection established
const response = new Response(null, { status: 200 });
const writableStream = new WritableStream({
write(chunk) {
tcpConn.write(chunk);
}
});
await response.body?.pipeTo(writableStream);
req.respondWith(response);
// Bidirectional data forwarding
const [clientReader, clientWriter] = Object.values(req.body?.pipeThrough(
new TransformStream()
) || {});
const [serverReader, serverWriter] = Object.values(tcpConn.readable.pipeThrough(
new TransformStream()
) || {});
// Implement bidirectional data forwarding...
}
async function handleHttpProxy(req: Request) {
// Parse target URL
const url = new URL(req.url.replace(/^http:\/\/[^/]+/, ""));
// Forward request
const forwardedReq = new Request(url.href, {
method: req.method,
headers: req.headers,
body: req.body
});
const response = await fetch(forwardedReq);
req.respondWith(response);
}
// Run: deno run --allow-net proxy_server.tsNetwork Security Practices
TLS/SSL Configuration
HTTPS Server
// https_server.ts
import { serveTls } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serveTls({
port: 443,
certFile: "./cert.pem",
keyFile: "./key.pem",
});
console.log("HTTPS server running on https://localhost:443");
for await (const req of server) {
req.respond({
status: 200,
headers: new Headers({ "Content-Type": "text/plain" }),
body: "Hello from HTTPS server!\n"
});
}
// Run: deno run --allow-net --allow-read https_server.tsCertificate Generation Command
# Generate self-signed certificate (for development)
openssl req -x509 -newkey rsa:4096 -nodes \
-keyout key.pem -out cert.pem -days 365 \
-subj "/CN=localhost"Security Protection Measures
Rate Limiting Implementation
// rate_limiter.ts
class RateLimiter {
private requests: Map<string, number[]> = new Map();
constructor(
private windowMs: number = 60 * 1000, // 1-minute window
private maxRequests: number = 100 // Maximum requests
) {}
check(ip: string): boolean {
const now = Date.now();
const timestamps = this.requests.get(ip) || [];
// Remove expired requests
const validTimestamps = timestamps.filter(t => t > now - this.windowMs);
if (validTimestamps.length >= this.maxRequests) {
return false; // Exceeds limit
}
validTimestamps.push(now);
this.requests.set(ip, validTimestamps);
return true;
}
}
// Usage example
const limiter = new RateLimiter();
for await (const req of serve({ port: 8000 })) {
const ip = req.conn.remoteAddr.hostname;
if (!limiter.check(ip)) {
req.respond({ status: 429, body: "Too Many Requests\n" });
continue;
}
req.respond({ status: 200, body: "OK\n" });
}CORS Middleware
// cors_middleware.ts
function corsMiddleware(handler: (req: Request) => Promise<Response>) {
return async (req: Request): Promise<Response> => {
// Handle preflight request
if (req.method === "OPTIONS") {
return new Response(null, {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
"Access-Control-Allow-Headers": "Content-Type"
}
});
}
// Handle actual request
const response = await handler(req);
// Add CORS headers
response.headers.set("Access-Control-Allow-Origin", "*");
response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.headers.set("Access-Control-Allow-Headers", "Content-Type");
return response;
};
}
// Usage example
const handler = corsMiddleware(async (req: Request) => {
return new Response("CORS enabled response\n");
});
serve(handler, { port: 8000 });Performance Optimization Techniques
Connection Pool Implementation
TCP Connection Pool
// connection_pool.ts
class ConnectionPool {
private pool: Deno.Conn[] = [];
private maxSize: number;
private host: string;
private port: number;
constructor(host: string, port: number, maxSize: number = 10) {
this.host = host;
this.port = port;
this.maxSize = maxSize;
}
async getConnection(): Promise<Deno.Conn> {
// Try to get available connection from pool
if (this.pool.length > 0) {
return this.pool.pop()!;
}
// Pool empty, create new connection
if (this.pool.length < this.maxSize) {
return Deno.connect({ hostname: this.host, port: this.port });
}
// Pool full, wait for connection release
throw new Error("Connection pool exhausted");
}
releaseConnection(conn: Deno.Conn) {
if (this.pool.length < this.maxSize) {
this.pool.push(conn);
} else {
conn.close(); // Pool full, close connection
}
}
}
// Usage example
const pool = new ConnectionPool("127.0.0.1", 8000, 5);
async function makeRequest() {
const conn = await pool.getConnection();
try {
await conn.write(new TextEncoder().encode("PING"));
const buffer = new Uint8Array(1024);
const bytesRead = await conn.read(buffer);
console.log("Response:", new TextDecoder().decode(buffer.subarray(0, bytesRead)));
} finally {
pool.releaseConnection(conn);
}
}
// Run multiple requests to test connection pool
Array(10).fill(0).forEach(makeRequest);Zero-Copy File Transfer
Efficient File Serving
// file_server_zero_copy.ts
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serve({ port: 8000 });
console.log("Zero-copy file server running on http://localhost:8000");
for await (const req of server) {
const filePath = `./files${req.url}`;
try {
// Get file info
const fileInfo = await Deno.stat(filePath);
if (fileInfo.isDirectory) {
req.respond({ status: 400, body: "Directories not supported\n" });
continue;
}
// Use send for zero-copy transfer
const file = await Deno.open(filePath, { read: true });
const response = new Response(file.readable, {
headers: new Headers({
"Content-Type": "application/octet-stream",
"Content-Length": fileInfo.size.toString()
})
});
req.respondWith(response);
file.close();
} catch (error) {
if (error instanceof Deno.errors.NotFound) {
req.respond({ status: 404, body: "File not found\n" });
} else {
console.error("Error:", error);
req.respond({ status: 500, body: "Internal server error\n" });
}
}
}
// Run: deno run --allow-read --allow-net file_server_zero_copy.tsPractical Case Study
Real-Time Chat Server
// chat_server.ts
import { serve } from "https://deno.land/std@0.140.0/http/server.ts";
const server = serve({ port: 8080 });
console.log("Chat server running on ws://localhost:8080");
// Store all connected clients
const clients: WebSocket[] = [];
for await (const req of server) {
if (req.headers.get("upgrade")?.toLowerCase() !== "websocket") {
req.respond({ status: 400, body: "Not a WebSocket request\n" });
continue;
}
const { socket, response } = Deno.upgradeWebSocket(req);
clients.push(socket);
console.log(`New client connected. Total: ${clients.length}`);
socket.onmessage = (e) => {
// Broadcast message to all clients
for (const client of clients) {
if (client !== socket && client.readyState === WebSocket.OPEN) {
client.send(e.data);
}
}
};
socket.onclose = () => {
const index = clients.indexOf(socket);
if (index !== -1) {
clients.splice(index, 1);
console.log(`Client disconnected. Total: ${clients.length}`);
}
};
socket.onerror = (e) => {
console.error("WebSocket error:", e);
socket.close();
};
req.respondWith(response);
}
// Run: deno run --allow-net chat_server.tsComplementary WebSocket Client
// chat_client.ts
const socket = new WebSocket("ws://localhost:8080");
socket.onopen = () => {
console.log("Connected to chat server");
socket.send("Hello from client!");
};
socket.onmessage = (e) => {
console.log("Received message:", e.data);
};
socket.onclose = () => console.log("Disconnected from server");
socket.onerror = (e) => console.error("WebSocket error:", e);
// Read input from console and send
Deno.stdin.setRawMode!(true);
for await (const line of Deno.stdin.readable.pipeThrough(
new TextDecoderStream()
)) {
if (line.trim()) {
socket.send(line.trim());
}
if (line === "exit\n") break;
}
socket.close();



