Echo server: Difference between revisions

m
m (→‎{{header|Wren}}: Minor tidy)
 
(37 intermediate revisions by 18 users not shown)
Line 5:
 
The implementation must not stop responding to other clients if one client sends a partial line or stops reading responses.
 
=={{header|Ada}}==
{{works with|GNAT}}
Line 10 ⟶ 11:
single-threaded, one client served at a time.
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO;
with Ada.IO_Exceptions;
with GNAT.Sockets;
Line 22 ⟶ 23:
GNAT.Sockets.Set_Socket_Option
(Socket => Receiver,
Level => GNAT.Sockets.Socket_Level,
Option => (Name => GNAT.Sockets.Reuse_Address, Enabled => True));
GNAT.Sockets.Bind_Socket
Line 47 ⟶ 49:
GNAT.Sockets.Close_Socket (Connection);
end loop;
end Echo_Server;</langsyntaxhighlight>
 
Multi-threaded, multiple clients served. On OS X 10.10.5 with gcc 4.9.1, serves a maximum of about 2000 threads (communication tasks) per process.
<syntaxhighlight lang="ada">
<lang Ada>
with Ada.Text_IO;
with Ada.IO_Exceptions;
Line 165 ⟶ 167:
GNAT.Sockets.Set_Socket_Option
(Socket => Receiver,
Level => GNAT.Sockets.Socket_Level,
Option => (Name => GNAT.Sockets.Reuse_Address, Enabled => True));
GNAT.Sockets.Bind_Socket
Line 195 ⟶ 198:
end echo_server_multi;
 
</syntaxhighlight>
</lang>
 
=={{header|Aime}}==
<langsyntaxhighlight lang="aime">void
readc(dispatch w, file i, file o, data b)
{
Line 248 ⟶ 251:
 
0;
}</langsyntaxhighlight>
 
=={{header|AutoHotkey}}==
<tt>echoserver.ahk</tt>, modified from
[http://www.autohotkey.com/forum/topic13829.html script] by zed gecko.
<langsyntaxhighlight AutoHotkeylang="autohotkey">#SingleInstance Force
Network_Port = 12321
Network_Address = 127.0.0.1
Line 452 ⟶ 455:
ExitSub:
DllCall("Ws2_32\WSACleanup")
ExitApp</langsyntaxhighlight>
A [[/AutoHotkey Client|client]] is also available for testing this code.
 
=={{header|BBC BASIC}}==
==={{header|BaCon}}===
<syntaxhighlight lang="bacon">OPEN "localhost:12321" FOR SERVER AS echo
WHILE TRUE
fd = ACCEPT(echo)
PRINT "Incoming connection from: ", GETPEER$(fd)
RECEIVE data$ FROM fd
SEND data$ & CR$ & NL$ TO fd
CLOSE SERVER fd
WEND</syntaxhighlight>
Input from other terminal:
<pre># echo "Hello world" | netcat 127.0.0.1 12321
Hello world
 
# echo "Hello world" | netcat 127.0.0.1 12321
Hello world
 
# echo "Hello world" | netcat 127.0.0.1 12321
Hello world
 
# echo "Hello world" | netcat 127.0.0.1 12321
Hello world</pre>
Output:
<pre>Incoming connection from: 127.0.0.1:36778
Incoming connection from: 127.0.0.1:36780
Incoming connection from: 127.0.0.1:36782
Incoming connection from: 127.0.0.1:36784</pre>
 
==={{header|BBC BASIC}}===
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> INSTALL @lib$+"SOCKLIB"
PROC_initsockets
Line 510 ⟶ 541:
WAIT 0
UNTIL FALSE
END</langsyntaxhighlight>
'''Sample output:'''
<pre>
Line 522 ⟶ 553:
Connection on socket 1012 closed
</pre>
 
==={{header|PureBasic}}===
<syntaxhighlight lang="purebasic">NewMap RecData.s()
OpenWindow(0, 100, 200, 200, 100, "Echo Server", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget )
InitNetwork()
CreateNetworkServer(1, 12321)
 
Repeat
Event = NetworkServerEvent()
ClientID = EventClient()
If Event = #PB_NetworkEvent_Connect ; When a new client has been connected...
AddMapElement(RecData(), Str(ClientID))
ElseIf Event = #PB_NetworkEvent_Data
*Buffer = AllocateMemory(20000)
count = ReceiveNetworkData(ClientID, *Buffer, 20000)
For i = 1 To count
RecData(Str(ClientID)) + Mid( PeekS(*Buffer, count), i , 1)
If Right( RecData(Str(ClientID)), 2) = #CRLF$
SendNetworkString (ClientID, RecData(Str(ClientID)))
Debug IPString(GetClientIP(ClientID)) + ":" + Str(GetClientPort(ClientID)) + " " + RecData(Str(ClientID))
RecData(Str(ClientID)) = ""
EndIf
Next
FreeMemory(*Buffer)
ElseIf Event = #PB_NetworkEvent_Disconnect ; When a client has closed the connection...
DeleteMapElement(RecData(), Str(ClientID))
EndIf
 
Event = WaitWindowEvent(10)
Until Event = #PB_Event_CloseWindow</syntaxhighlight>
 
==={{header|REALbasic}}===
This example uses the built-in ServerSocket class to handle multiple users.
<syntaxhighlight lang="vb">
Class EchoSocket
Inherits TCPSocket
Sub DataAvailable()
If Instr(Me.LookAhead, EndofLine.Windows) > 0 Then
Dim data As String = Me.ReadAll
Dim lines() As String = Split(data, EndofLine.Windows)
For i As Integer = 0 To Ubound(lines)
Me.Write(lines(i) + EndOfLine.Windows)
Print(lines(i))
Next
End If
End Sub
End Class
 
Class EchoServer
Inherits ServerSocket
Function AddSocket() As TCPSocket
Return New EchoSocket
End Function
End Class
 
Class App
Inherits ConsoleApplication
Function Run(args() As String) As Integer
Listener = New EchoServer
Listener.Port = 12321
Listener.Listen()
While True
DoEvents() 'pump the event loop
Wend
End Function
Private Listener As EchoServer
End Class
</syntaxhighlight>
 
=={{header|C}}==
Line 527 ⟶ 629:
This is a rather standard code (details apart); the reference guide for such a code is the [http://beej.us/guide/bgnet Beej's Guide to Network programming]. The dependency from POSIX is mainly in the use of the <tt>read</tt> and <tt>write</tt> functions, (using the socket as a file descriptor sometimes make things simpler).
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 644 ⟶ 746:
take_connections_forever(sock);
return EXIT_SUCCESS;
}</langsyntaxhighlight>
 
=={{header|C sharp|C#}}==
<langsyntaxhighlight lang="csharp">using System.Net.Sockets;
using System.Threading;
 
Line 709 ⟶ 811:
}
}
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
<langsyntaxhighlight lang="lisp">(use '[clojure.contrib.server-socket :only (create-server)])
(use '[clojure.contrib.duck-streams :only (read-lines write-lines)])
 
Line 718 ⟶ 820:
(write-lines (java.io.PrintWriter. output true) (read-lines input)))
 
(create-server 12321 echo)</langsyntaxhighlight>
 
Note here that an auto-flushing PrintWriter needs to be created, otherwise 'output' could simply be passed to write-lines.
Line 725 ⟶ 827:
{{trans|JavaScript}}
{{works with|node.js}}
<langsyntaxhighlight lang="coffeescript">
net = require("net")
server = net.createServer (conn) ->
Line 743 ⟶ 845:
 
server.listen 12321, "localhost"
</syntaxhighlight>
</lang>
 
=={{header|Common Lisp}}==
Line 749 ⟶ 851:
Here is a basic [http://common-lisp.net/project/usocket/ :usocket] example (it should work with any Common Lisp):
 
<langsyntaxhighlight lang="lisp">(ql:quickload (list :usocket))
(defpackage :echo (:use :cl :usocket))
(in-package :echo)
Line 773 ⟶ 875:
 
(echo-server 12321)
</syntaxhighlight>
</lang>
 
It's single threaded, so you can't REPL around with a running server. You'll need to start a second Lisp prompt, load the above and
 
<langsyntaxhighlight lang="lisp">(defun echo-send (message port)
(with-client-socket (sock str "127.0.0.1" port)
(write-string message str)
Line 785 ⟶ 887:
 
(echo-send "Hello echo!" 12321)
</syntaxhighlight>
</lang>
 
The return value of that call should be "You said: Hello echo!".
Line 792 ⟶ 894:
 
The usocket library notwithstanding, sockets are not a standard part of Common Lisp, but many implementations provide them. Here is a CLISP-specific example: {{works with|CLISP}}
<langsyntaxhighlight lang="lisp">(defvar *clients* '()
"This is a list of (socket :input status) which is used with
`socket:socket-status' to test for data ready on a socket.")
Line 838 ⟶ 940:
(setq *clients* (remove socket *clients* :key #'car)))
 
(echo-server 12321)</langsyntaxhighlight>
 
=={{header|D}}==
This is a very basic server that processes the buffers one character at a time. In a real-world application, the buffers would be larger. More seriously, it processes one listener at a time. If the <code>currSock.receive()</code> blocks, the loop will not process other clients. This opens the door for a trivial denial-of-service attack. A realistic echo service must multiplex clients.
<langsyntaxhighlight lang="d">import std.array, std.socket;
 
void main() {
Line 861 ⟶ 963:
buff.clear();
}
}</langsyntaxhighlight>
 
This example will handle many connections.
<langsyntaxhighlight lang="d">import std.stdio, std.socket, std.array;
 
void main() {
Line 972 ⟶ 1,074:
}
}
}</langsyntaxhighlight>
 
=={{header|Delphi}}==
<langsyntaxhighlight Delphilang="delphi">program EchoServer;
 
{$APPTYPE CONSOLE}
Line 1,032 ⟶ 1,134:
lEchoServer.Free;
end;
end.</langsyntaxhighlight>
 
=={{header|Erlang}}==
<langsyntaxhighlight lang="erlang">-module(echo).
-export([start/0]).
 
Line 1,057 ⟶ 1,159:
{tcp_closed, Conn} ->
io:format("Connection closed: ~p~n", [Conn])
end.</langsyntaxhighlight>
 
=={{header|Elixir}}==
<PRE>
defmodule Echo.Server do
def start(port) do
tcp_options = [:binary, {:packet, 0}, {:active, false}]
{:ok, socket} = :gen_tcp.listen(port, tcp_options)
listen(socket)
end
 
defp listen(socket) do
{:ok, conn} = :gen_tcp.accept(socket)
spawn(fn -> recv(conn) end)
listen(socket)
end
 
defp recv(conn) do
case :gen_tcp.recv(conn, 0) do
{:ok, data} ->
:gen_tcp.send(conn, data)
recv(conn)
{:error, :closed} ->
:ok
end
end
end
</PRE>
 
=={{header|F Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">open System.IO
open System.Net
open System.Net.Sockets
Line 1,089 ⟶ 1,218:
let main _ =
EchoService
0</langsyntaxhighlight>
 
=={{header|Factor}}==
Connections get logged to <code>/place-where-factor-is/logs/echo-server</code>.
<langsyntaxhighlight lang="factor">USING: accessors io io.encodings.utf8 io.servers io.sockets threads ;
IN: rosetta.echo
 
Line 1,109 ⟶ 1,238:
: start-echo-server ( -- )
<echo-server> [ start-server ] in-thread start-server drop ;
</syntaxhighlight>
</lang>
 
=={{header|Forth}}==
{{works with|GNU Forth|0.7.0}}
<langsyntaxhighlight lang="forth">include unix/socket.fs
 
128 constant size
Line 1,142 ⟶ 1,271:
again ;
 
12321 echo-server</langsyntaxhighlight>
''TODO: use tasker.fs and non-blocking semantics to handle mutliple connections''
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,176 ⟶ 1,305:
go echo(s, i)
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
 
<langsyntaxhighlight lang="haskell">module Main where
import Network (withSocketsDo, accept, listenOn, sClose, PortID(PortNumber))
import Control.Monad (forever)
Line 1,204 ⟶ 1,333:
acc@(_, host, port) <- accept listener
putStrLn $ "Accepted connection from " ++ show (host, port)
forkIO (echo acc)</langsyntaxhighlight>
 
==Icon and {{header|Unicon}}==
 
The following is Unicon-specific:
<langsyntaxhighlight lang="unicon">global mlck, nCons
 
procedure main()
Line 1,226 ⟶ 1,355:
critical mlck: nCons -:= 1
}
end</langsyntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
 
public class EchoServer {
ServerSocket serverSocket;
public EchoServer(){
}
public void start() {
try {
serverSocket = new ServerSocket(12321);
while(true){
Thread clientThread = new Thread(new ClientHandler(serverSocket.accept()));
clientThread.start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
System.out.println("closing server socket");
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
EchoServer es = new EchoServer();
es.start();
}
}
 
public static void main(String[] args) throws IOException {
class ClientHandler implements Runnable {
try (ServerSocket listener = new ServerSocket(12321)) {
private static int numConnections;
while (true) {
private int connectionId = 0;
Socket conn = listener.accept();
Socket clientSocket;
Thread clientThread = new Thread(() -> handleClient(conn));
clientThread.start();
public ClientHandler(Socket s) {
}
connectionId = numConnections++;
}
System.out.println("handling connection, #" + connectionId);
}
clientSocket = s;
}
 
private static void handleClient(Socket connArg) {
public void run() {
Charset utf8 = StandardCharsets.UTF_8;
PrintWriter out = null;
 
BufferedReader in = null;
try (Socket conn = connArg) {
try {
BufferedReader in = new BufferedReader(
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader( new InputStreamReader(clientSocketconn.getInputStream(), utf8));
 
String inputLine, outputLine;
PrintWriter out = new PrintWriter(
while((inputLine = in.readLine()) != null){
new OutputStreamWriter(conn.getOutputStream(), utf8),
outputLine = inputLine;
true);
System.out.println("received: " + outputLine);
 
out.write(outputLine+"\n");
String line;
out.flush();
while ((line = in.readLine()) != null) {
if (outputLine.equals("exit"))
out.println(line);
break;
}
}
} catch (ExceptionIOException e) {
e.printStackTrace();
}
} finally {
}
out.close();
}</syntaxhighlight>
try {
in.close();
clientSocket.close();
System.out.println("closing connection, #" + connectionId);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}</lang>
 
=={{header|JavaScript}}==
{{works with|Node.js}}
<langsyntaxhighlight lang="javascript">varconst net = require('net');
 
function handleClient(conn) {
var server = net.createServer(function(conn) {
console.log("'Connection from "' + conn.remoteAddress + "' on port "' + conn.remotePort);
conn.setEncoding("utf8");
var buffer = "";
 
conn.setEncoding('utf-8');
conn.on("data", function(data) {
 
for(var i = 0; i <= data.length; i++) {
let var charbuffer = data.charAt(i)'';
 
buffer += char;
function ifhandleData(char == "\n"data) {
for (let i = 0; i < data.length; i++) {
conn.write(buffer);
buffer const char = ""data.charAt(i);
} buffer += char;
if (char === '\n') {
conn.write(buffer);
buffer = '';
}
}
}
});
});
 
conn.on('data', handleData);
server.listen(12321, "localhost");</lang>
}
 
net.createServer(handleClient).listen(12321, 'localhost');</syntaxhighlight>
 
=={{header|Julia}}==
<syntaxhighlight lang="julia">
using Sockets # for version 1.0
println("Echo server on port 12321")
try
server = listen(12321)
instance = 0
while true
sock = accept(server)
instance += 1
socklabel = "$(getsockname(sock)) number $instance"
@async begin
println("Server connected to socket $socklabel")
write(sock, "Connected to echo server.\r\n")
while isopen(sock)
str = readline(sock)
write(sock,"$str\r\n")
println("Echoed $str to socket $socklabel")
end
println("Closed socket $socklabel")
end
end
catch y
println("Caught exception: $y")
end
</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|Java}}
<syntaxhighlight lang ="scala">// versionimport 1java.1net.3ServerSocket
 
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.ServerSocket
import java.net.Socket
 
fun main() {
class ClientHandler(private val clientSocket: Socket): Runnable {
private val connectionId: Int
 
fun handleClient(conn: Socket) {
init {
connectionIdconn.use = ++numConnections{
val input = conn.inputStream.bufferedReader()
println("Handling connection, #$connectionId")
val output = conn.outputStream.bufferedWriter()
}
 
input.forEachLine { line ->
override fun run() {
output.write(line)
val pw = PrintWriter(clientSocket.outputStream, true)
output.newLine()
val br = BufferedReader(InputStreamReader(clientSocket.inputStream))
while output.flush(true) {
val line = br.readLine() ?: break}
println("Received: $line")
pw.write("$line\n")
pw.flush()
if (line == "exit") break
}
br.close()
pw.close()
clientSocket.close()
println("Closing connection, #$connectionId")
}
 
ServerSocket(12321).use { listener ->
private companion object {
var numConnections = 0
}
}
 
fun main(args: Array<String>) {
val serverSocket = ServerSocket(12321)
try {
while (true) {
Thread(ClientHandler(serverSocket val conn = listener.accept())).start()
Thread { handleClient(conn) }.start()
}
}
}
finally {
</syntaxhighlight>
serverSocket.close()
println("Closing server socket")
}
}</lang>
 
{{out}}
Quick test using telnetnetcat:
<pre>telnetnc localhost 12321
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Hello
Hello
Goodbye
Goodbye
</pre>
exit
exit
Connection closed by foreign host.</pre>
 
Echo server window (closing with ^C):
<pre>Handling connection, #1
Received: Hello
Received: Goodbye
Received: exit
Closing connection, #1
^C</pre>
 
=={{header|LFE}}==
Line 1,410 ⟶ 1,497:
 
Paste into the LFE REPL:
<langsyntaxhighlight lang="lisp">
(defun start ()
(spawn (lambda ()
Line 1,429 ⟶ 1,516:
(`#(tcp_closed ,conn)
(lfe_io:format "Connection closed: ~p~n" (list conn)))))
</syntaxhighlight>
</lang>
 
Usage:
Line 1,443 ⟶ 1,530:
 
=={{header|Lua}}==
{{works with|Lua|5.3}}
{{libheader|LuaSocket}}
 
This implementation doesn't rely on coroutines because they're an additional (often confusing) notion that could make the example needlessly hard to understand. Instead it uses a table of not-quite-non-blocking socket client objects (they block for one microsecond), which is iterated over to check on whether each one has either a line to echo or an error to warrant deletion.
<langsyntaxhighlight Lualang="lua">local socket = require("socket")
 
local function has_value(tab, value)
for i, v in ipairs(tab) do
if v == value then return i end
end
return false
end
 
local function checkOn(client)
local line, err = client:receive()
if line then
client:send(line .. "\n")
end
if err and err ~= "timeout" then
print(tostring(client) .. " " .. err)
client:close()
return true -- end this connection
end
return false -- do not end this connection
end
 
local server = assert(socket.bind("*",12321))
server:settimeout(0) -- make non-blocking
local connections = { } -- a list of the client connections
while true do
local newClient = server:accept()
if newClient then
newClient:settimeout(0) -- make non-blocking
table.insert(connections, newClient)
end
local readList = socket.select({server, table.unpack(connections)})
for _, conn in ipairs(readList) do
if conn ~= server and checkOn(conn) then
table.remove(connections, has_value(connections, conn))
end
end
end</syntaxhighlight>
----
The following implementation uses tiny delays rather than socket.select. It uses a table of not-quite-non-blocking socket client objects (they block for 4 milliseconds), which is iterated over to check on whether each one has either a line to echo or an error to warrant deletion. Without the millisecond delays, the whole thing would become one 'hot' loop and eat all the CPU time for one core. With them, it uses close to zero percent.
<syntaxhighlight lang="lua">local socket=require("socket")
 
function checkOn (client)
Line 1,456 ⟶ 1,584:
print(tostring(client) .. " " .. err)
client:close()
return errtrue -- end this connection
end
return nilfalse -- do not end this connection
end
 
local delay, clients,= newClient0.004 = 10^-6,- anything less than this uses up my {}CPU
local connections = {} -- an array of connections
local newClient
local server = assert(socket.bind("*", 12321))
server:settimeout(delay)
while true do
print("Server started")
while 1 do
repeat
newClient = server:accept()
for kidx, vclient in pairsipairs(clientsconnections) do
if checkOn(vclient) then table.remove(clientsconnections, kidx) end
end
until newClient
newClient:settimeout(delay)
print(tostring(newClient) .. " connected")
table.insert(clientsconnections, newClient)
end</langsyntaxhighlight>
----
Without the microsecond delays, the whole thing would become one 'hot' loop and eat all the CPU time for one core. With them, it uses close to zero percent.
 
{{works with|Luvit}}
 
<syntaxhighlight lang="lua">local http = require("http")
 
http.createServer(function(req, res)
print(("Connection from %s"):format(req.socket:address().ip))
 
local chunks = {}
local function dumpChunks()
for i=1,#chunks do
res:write(table.remove(chunks, 1))
end
end
 
req:on("data", function(data)
for line, nl in data:gmatch("([^\n]+)(\n?)") do
if nl == "\n" then
dumpChunks()
res:write(line)
res:write("\n")
else
table.insert(chunks, line)
end
end
end)
 
req:on("end", function()
dumpChunks()
res:finish()
end)
end):listen(12321, "127.0.0.1")
 
print("Server running at http://127.0.0.1:12321/")</syntaxhighlight>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
This will be able to handle multiple connections and multiple echoes:
<syntaxhighlight lang="mathematica">server = SocketOpen[12321];
SocketListen[server, Function[{assoc},
With[{client = assoc["SourceSocket"], input = assoc["Data"]},
WriteString[client, ByteArrayToString[input]];
]
]]</syntaxhighlight>
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">import asyncnet, asyncdispatch
 
proc processClient(client: AsyncSocket) {.async.} =
Line 1,493 ⟶ 1,665:
while true:
let client = await server.accept()
echo "Accepting connection from client", client.getLocalAddr[0]
discard processClient(client)
 
discard serve()
runForever()</langsyntaxhighlight>
 
=={{header|Objeck}}==
<langsyntaxhighlight lang="objeck">
use Net;
use Concurrency;
Line 1,536 ⟶ 1,709:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Ol}}==
<syntaxhighlight lang="scheme">
(define (timestamp) (syscall 201 "%c"))
 
(define (on-accept name fd)
(lambda ()
(print "# " (timestamp) "> we got new visitor: " name)
 
(let*((ss1 ms1 (clock)))
(let loop ((str #null) (stream (force (port->bytestream fd))))
(cond
((null? stream)
#false)
((function? stream)
(let ((message (list->string (reverse str))))
(print "# " (timestamp) "> client " name " wrote " message)
(print-to fd message))
(loop #null (force stream)))
(else
(loop (cons (car stream) str) (cdr stream)))))
(syscall 3 fd)
(let*((ss2 ms2 (clock)))
(print "# " (timestamp) "> visitor leave us. It takes " (+ (* (- ss2 ss1) 1000) (- ms2 ms1)) "ms.")))))
 
(define (run port)
(let ((socket (syscall 41)))
; bind
(let loop ((port port))
(if (not (syscall 49 socket port)) ; bind
(loop (+ port 2))
(print "Server binded to " port)))
; listen
(if (not (syscall 50 socket)) ; listen
(shutdown (print "Can't listen")))
 
; accept
(let loop ()
(if (syscall 23 socket) ; select
(let ((fd (syscall 43 socket))) ; accept
(fork (on-accept (syscall 51 fd) fd))))
(sleep 0)
(loop))))
 
(run 12321)
</syntaxhighlight>
 
=={{header|Oz}}==
<langsyntaxhighlight lang="oz">declare
ServerSocket = {New Open.socket init}
 
Line 1,574 ⟶ 1,793:
{ClientSocket close}
end
end</langsyntaxhighlight>
 
Client test code:
<langsyntaxhighlight lang="oz">declare
Socket = {New class $ from Open.socket Open.text end init}
in
Line 1,583 ⟶ 1,802:
{Socket write(vs:"Hello\n")}
{System.showInfo "Client received: "#{Socket getS($)}}
{Socket close}</langsyntaxhighlight>
 
Example session:
Line 1,599 ⟶ 1,818:
 
This is an example using the [http://search.cpan.org/perldoc?IO::Socket IO::Socket] module:
<langsyntaxhighlight lang="perl">use IO::Socket;
my $use_fork = 1;
 
Line 1,627 ⟶ 1,846:
}
 
# child will reach here and close its copy of $sock before exit</langsyntaxhighlight>
 
This is an equivalent program using the [http://search.cpan.org/perldoc?Net::Server Net::Server] module:
<langsyntaxhighlight lang="perl">package Echo;
use base 'Net::Server::Fork';
sub process_request {
print while <STDIN>;
}
Echo->run(port => 12321, log_level => 3);</langsyntaxhighlight>
It also prints the IP address and port number of every connection.
 
This is a more complicated example using preforking:
<langsyntaxhighlight lang="perl">package Echo;
use base 'Net::Server::PreFork';
sub process_request {
print while <STDIN>;
}
Echo->run(port => 12321, log_level => 3);</langsyntaxhighlight>
By default it spawns 5 child processes at startup, makes sure there are always at least 2 and at most 10 spare children available for new requests, each of which will be killed after processing 1000 requests and new ones will take their place.
=={{header|Perl 6}}==
{{Works with|rakudo|2018.03}}
<lang perl6>my $socket = IO::Socket::INET.new:
:localhost<localhost>,
:localport<12321>,
:listen;
 
=={{header|Phix}}==
while $socket.accept -> $conn {
<!--<syntaxhighlight lang="phix">(notonline)-->
say "Accepted connection";
<span style="color: #000080;font-style:italic;">-- demo\rosetta\EchoServer.exw</span>
start {
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
while $conn.recv -> $stuff {
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">sockets</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
say "Echoing $stuff";
<span style="color: #008080;">constant</span> <span style="color: #000000;">ESCAPE</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">#1B</span>
$conn.print($stuff);
<span style="color: #008080;">procedure</span> <span style="color: #000000;">echo</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">sockd</span><span style="color: #0000FF;">)</span>
}
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"socket opened"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sockd</span><span style="color: #0000FF;">}</span>
$conn.close;
<span style="color: #004080;">string</span> <span style="color: #000000;">buffer</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
}
<span style="color: #004080;">integer</span> <span style="color: #000000;">bytes_sent</span>
}</lang>
<span style="color: #004080;">bool</span> <span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
 
<span style="color: #008080;">while</span> <span style="color: #004600;">true</span> <span style="color: #008080;">do</span>
Async version:
<span style="color: #0000FF;">{</span><span style="color: #004080;">integer</span> <span style="color: #000000;">len</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">recv</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sockd</span><span style="color: #0000FF;">)</span>
<lang perl6>react {
<span style="color: #008080;">if</span> <span style="color: #000000;">len</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
whenever IO::Socket::Async.listen('0.0.0.0', 12321) -> $conn {
<span style="color: #008080;">if</span> <span style="color: #000000;">first</span> <span style="color: #008080;">then</span>
whenever $conn.Supply.lines -> $line {
<span style="color: #000000;">bytes_sent</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">send</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sockd</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- partial echo, see note</span>
$conn.print( "$line\n" ) ;
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">false</span>
}
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
}
<span style="color: #000000;">buffer</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">s</span>
}
<span style="color: #008080;">if</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[$]=</span><span style="color: #008000;">'\n'</span> <span style="color: #008080;">then</span>
</lang>
<span style="color: #000000;">bytes_sent</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">send</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sockd</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">buffer</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">buffer</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"socket disconnected"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sockd</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">list_s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">socket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">AF_INET</span><span style="color: #0000FF;">,</span><span style="color: #000000;">SOCK_STREAM</span><span style="color: #0000FF;">,</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">pSockAddr</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sockaddr_in</span><span style="color: #0000FF;">(</span><span style="color: #000000;">AF_INET</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">12321</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">list_s</span><span style="color: #0000FF;"><</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">bind</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list_s</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">pSockAddr</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">SOCKET_ERROR</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"bind (%v)"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">get_socket_error</span><span style="color: #0000FF;">()})</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">listen</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list_s</span><span style="color: #0000FF;">,</span><span style="color: #000000;">100</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">SOCKET_ERROR</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"listen (%v)"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">get_socket_error</span><span style="color: #0000FF;">()})</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"echo server started, press escape or q to exit\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #008080;">not</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">get_key</span><span style="color: #0000FF;">(),{</span><span style="color: #000000;">ESCAPE</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'q'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'Q'</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">do</span>
<span style="color: #0000FF;">{</span><span style="color: #004080;">integer</span> <span style="color: #000000;">code</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">select</span><span style="color: #0000FF;">({</span><span style="color: #000000;">list_s</span><span style="color: #0000FF;">},{},{},</span><span style="color: #000000;">250000</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (0.25s)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">code</span><span style="color: #0000FF;">=</span><span style="color: #000000;">SOCKET_ERROR</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"select (%v)"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">get_socket_error</span><span style="color: #0000FF;">()})</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">code</span><span style="color: #0000FF;">></span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (not timeout)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">conn_s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">accept</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list_s</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">conn_s</span><span style="color: #0000FF;">=</span><span style="color: #000000;">SOCKET_ERROR</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">hThread</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">create_thread</span><span style="color: #0000FF;">(</span><span style="color: #000000;">echo</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">conn_s</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">list_s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">closesocket</span><span style="color: #0000FF;">(</span><span style="color: #000000;">list_s</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">WSACleanup</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
Tested using telnet [-e q] localhost 12321<br>
Note: on windows, keying "abc" did not echo anything until the first return, so I added a partial echo: remove if not needed/wanted.
 
=={{header|PHP}}==
<langsyntaxhighlight PHPlang="php">$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
socket_bind($socket, '127.0.0.1', 12321);
socket_listen($socket);
Line 1,705 ⟶ 1,945:
}
}
}</langsyntaxhighlight>
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(setq Port (port 12321))
 
(loop
Line 1,723 ⟶ 1,963:
 
(prinl (stamp) " -- (Pid " *Pid ") Client disconnected")
(bye) # Terminate child</langsyntaxhighlight>
 
=={{header|PureBasic}}==
<lang Purebasic>NewMap RecData.s()
OpenWindow(0, 100, 200, 200, 100, "Echo Server", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget )
InitNetwork()
CreateNetworkServer(1, 12321)
 
Repeat
Event = NetworkServerEvent()
ClientID = EventClient()
If Event = #PB_NetworkEvent_Connect ; When a new client has been connected...
AddMapElement(RecData(), Str(ClientID))
ElseIf Event = #PB_NetworkEvent_Data
*Buffer = AllocateMemory(20000)
count = ReceiveNetworkData(ClientID, *Buffer, 20000)
For i = 1 To count
RecData(Str(ClientID)) + Mid( PeekS(*Buffer, count), i , 1)
If Right( RecData(Str(ClientID)), 2) = #CRLF$
SendNetworkString (ClientID, RecData(Str(ClientID)))
Debug IPString(GetClientIP(ClientID)) + ":" + Str(GetClientPort(ClientID)) + " " + RecData(Str(ClientID))
RecData(Str(ClientID)) = ""
EndIf
Next
FreeMemory(*Buffer)
ElseIf Event = #PB_NetworkEvent_Disconnect ; When a client has closed the connection...
DeleteMapElement(RecData(), Str(ClientID))
EndIf
 
Event = WaitWindowEvent(10)
Until Event = #PB_Event_CloseWindow</lang>
 
=={{header|Python}}==
{{works with|Python|2.3 or above}}
<langsyntaxhighlight lang="python">import SocketServer
 
HOST = "localhost"
Line 1,792 ⟶ 1,999:
# interrupt the program with Ctrl-C
print "server listening on %s:%s" % server.server_address
server.serve_forever()</langsyntaxhighlight>
 
{{works with|Python|3.5 or above}}
<syntaxhighlight lang="python">
#!/usr/bin/env python
# $ printf 'echo\r\n' | nc localhost 12321
# echo
import asyncio
import logging
import os
 
logger = logging.getLogger('echoserver')
 
async def echo_handler(reader, writer):
address = writer.get_extra_info('peername')
logger.debug('accept: %s', address)
message = await reader.readline()
writer.write(message)
await writer.drain()
writer.close()
 
if __name__ == '__main__':
logging.basicConfig()
logger.setLevel(logging.DEBUG)
loop = asyncio.get_event_loop()
factory = asyncio.start_server(
echo_handler,
os.environ.get('HOST'),
os.environ.get('PORT', 12321)
)
server = loop.run_until_complete(factory)
try:
loop.run_forever()
except KeyboardInterrupt:
pass
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()
</syntaxhighlight>
 
{{works with|Python|2 and 3}}
Using only the low-level socket and threading modules. Supports timing out inactive clients
<syntaxhighlight lang="python">
#!usr/bin/env python
import socket
import threading
 
HOST = 'localhost'
PORT = 12321
SOCKET_TIMEOUT = 30
 
# This function handles reading data sent by a client, echoing it back
# and closing the connection in case of timeout (30s) or "quit" command
# This function is meant to be started in a separate thread
# (one thread per client)
def handle_echo(client_connection, client_address):
client_connection.settimeout(SOCKET_TIMEOUT)
try:
while True:
data = client_connection.recv(1024)
# Close connection if "quit" received from client
if data == b'quit\r\n' or data == b'quit\n':
print('{} disconnected'.format(client_address))
client_connection.shutdown(1)
client_connection.close()
break
# Echo back to client
elif data:
print('FROM {} : {}'.format(client_address,data))
client_connection.send(data)
# Timeout and close connection after 30s of inactivity
except socket.timeout:
print('{} timed out'.format(client_address))
client_connection.shutdown(1)
client_connection.close()
 
# This function opens a socket and listens on specified port. As soon as a
# connection is received, it is transfered to another socket so that the main
# socket is not blocked and can accept new clients.
def listen(host, port):
# Create the main socket (IPv4, TCP)
connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
connection.bind((host, port))
# Listen for clients (max 10 clients in waiting)
connection.listen(10)
# Every time a client connects, allow a dedicated socket and a dedicated
# thread to handle communication with that client without blocking others.
# Once the new thread has taken over, wait for the next client.
while True:
current_connection, client_address = connection.accept()
print('{} connected'.format(client_address))
handler_thread = threading.Thread( \
target = handle_echo, \
args = (current_connection,client_address) \
)
# daemon makes sure all threads are killed if the main server process
# gets killed
handler_thread.daemon = True
handler_thread.start()
 
if __name__ == "__main__":
try:
listen(HOST, PORT)
except KeyboardInterrupt:
print('exiting')
pass
</syntaxhighlight>
 
=={{header|Racket}}==
 
An example echo server from the front page of the Racket website:
<langsyntaxhighlight lang="racket">
#lang racket
(define listener (tcp-listen 12321))
Line 1,804 ⟶ 2,118:
(thread (λ() (copy-port I O) (close-output-port O)))
(echo-server))
</syntaxhighlight>
</lang>
 
=={{header|REALbasicRaku}}==
(formerly Perl 6)
{{Works with|rakudo|2018.03}}
<syntaxhighlight lang="raku" line>my $socket = IO::Socket::INET.new:
:localhost<localhost>,
:localport<12321>,
:listen;
 
while $socket.accept -> $conn {
This example uses the built-in ServerSocket class to handle multiple users.
say "Accepted connection";
<lang vb>
start {
Class EchoSocket
while $conn.recv -> $stuff {
Inherits TCPSocket
say "Echoing $stuff";
Sub DataAvailable()
$conn.print($stuff);
If Instr(Me.LookAhead, EndofLine.Windows) > 0 Then
Dim data As String = Me.ReadAll}
$conn.close;
Dim lines() As String = Split(data, EndofLine.Windows)
}
For i As Integer = 0 To Ubound(lines)
}</syntaxhighlight>
Me.Write(lines(i) + EndOfLine.Windows)
Print(lines(i))
Next
End If
End Sub
End Class
 
Async version:
Class EchoServer
<syntaxhighlight lang="raku" line>react {
Inherits ServerSocket
whenever IO::Socket::Async.listen('0.0.0.0', 12321) -> $conn {
Function AddSocket() As TCPSocket
whenever $conn.Supply.lines -> $line {
Return New EchoSocket
$conn.print( "$line\n" ) ;
End Function
}
End Class
}
 
}
Class App
</syntaxhighlight>
Inherits ConsoleApplication
Function Run(args() As String) As Integer
Listener = New EchoServer
Listener.Port = 12321
Listener.Listen()
While True
DoEvents() 'pump the event loop
Wend
End Function
Private Listener As EchoServer
End Class
</lang>
 
=={{header|REBOL}}==
<langsyntaxhighlight lang="rebol">server-port: open/lines tcp://:12321
forever [
connection-port: first server-port
Line 1,855 ⟶ 2,159:
close connection-port
]
close server-port</langsyntaxhighlight>
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">require 'socket'
server = TCPServer.new(12321)
 
Line 1,877 ⟶ 2,181:
end
end
end</langsyntaxhighlight>
 
Ruby 1.9.2 introduced an alternate method to create TCP server sockets. The <code>Socket.tcp_server_loop</code> method encapsulates the guts of the server into a block.
{{works with|Ruby|1.9.2}}
<langsyntaxhighlight lang="ruby">require 'socket'
 
Socket.tcp_server_loop(12321) do |conn, addr|
Line 1,898 ⟶ 2,202:
end
end
end</langsyntaxhighlight>
 
=={{header|Rust}}==
<langsyntaxhighlight lang="rust">
use std::net::{TcpListener, TcpStream};
use std::io::{BufReader, BufRead, Write};
Line 1,929 ⟶ 2,233:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Scala}}==
<langsyntaxhighlight lang="scala">import java.io.PrintWriter
import java.net.{ServerSocket, Socket}
 
Line 1,942 ⟶ 2,246:
 
class ClientHandler(clientSocket: Socket) extends Runnable {
private val (connectionId, closeCmd) = ({numConnections += 1; numConnections}, ":exit")
 
override def run(): Unit =
new PrintWriter(clientSocket.getOutputStream, true) {
println(s"Connection opened, close with entering '$closeCmd'.")
Source.fromInputStream(clientSocket.getInputStream).getLines
.takeWhile(!_.toLowerCase.startsWith(":exit"closeCmd))
.foreach { line =>
Console.println(s"Received on #$connectionId: $line")
Line 1,953 ⟶ 2,260:
clientSocket.close()
}
 
private def connectionId: Int = {numConnections += 1; numConnections}
 
println(s"Handling connection, $connectionId")
Line 1,960 ⟶ 2,265:
 
while (true) new Thread(new ClientHandler(serverSocket.accept())).start()
}</langsyntaxhighlight>
 
=={{header|Scheme}}==
{{works with|Guile}}
Based on the [[Guile]] [http://www.gnu.org/software/guile/manual/html_node/Internet-Socket-Examples.html Internet Socket Server Example].
<langsyntaxhighlight lang="scheme">; Needed in Guile for read-line
(use-modules (ice-9 rdelim))
 
Line 2,005 ⟶ 2,310:
(primitive-exit))
; Parent waits for child to finish spawning grandchild
(waitpid child)))))</langsyntaxhighlight>
 
=={{header|Seed7}}==
Line 2,012 ⟶ 2,317:
requests from new and existing connections.
 
<langsyntaxhighlight Seed7lang="seed7">$ include "seed7_05.s7i";
include "socket.s7i";
include "listener.s7i";
Line 2,040 ⟶ 2,345:
end if;
end while;
end func;</langsyntaxhighlight>
 
=={{header|Tcl}}==
This code is single-threaded. It uses non-blocking I/O to perform the transfers, sitting on top of the event multiplexer system call (e.g., <code>select()</code> on Unix) to decide when to take new connections or service a particular socket. This makes this into a very lightweight echo server in terms of overall system resources.
 
<langsyntaxhighlight lang="tcl"># How to handle an incoming new connection
proc acceptEcho {chan host port} {
puts "opened connection from $host:$port"
Line 2,065 ⟶ 2,370:
# Make the server socket and wait for connections
socket -server acceptEcho -myaddr localhost 12321
vwait forever</langsyntaxhighlight>
===Alternative version===
A more succinct version (though one harder to adapt to other kinds of services, but closer to the standard unix echo daemon since it has no line-buffering) is to use an asynchronous binary copy.
<langsyntaxhighlight lang="tcl"># How to handle an incoming new connection
proc acceptEcho {chan host port} {
puts "opened connection from $host:$port"
Line 2,083 ⟶ 2,388:
# Make the server socket and wait for connections
socket -server acceptEcho -myaddr localhost 12321
vwait forever</langsyntaxhighlight>
 
=={{header|X86 Assembly}}==
<syntaxhighlight lang="x86asm">
 
; x86_64 Linux NASM
 
global _start
 
%define af_inet 2
%define sock_stream 1
%define default_proto 0
%define sol_sock 1
%define reuse_addr 2
%define reuse_port 15
%define server_port 9001
%define addr_any 0
%define family_offset 0
%define port_offset 2
%define addr_offset 4
%define unused_offset 8
%define addr_len 16
%define buffer_len 64
%define max_connections 3
 
 
section .text
 
; rdi - 16 bit value to be byte swapped
; return - byte swapped value
htn_swap16:
 
xor rax, rax
mov rdx, 0x000000ff
 
mov rsi, rdi
and rsi, rdx
shl rsi, 8
or rax, rsi
shl rdx, 8
 
mov rsi, rdi
and rsi, rdx
shr rsi, 8
or rax, rsi
ret
 
; return - server socket
create_server_socket:
 
mov rax, 41
mov rdi, af_inet
mov rsi, sock_stream
mov rdx, default_proto
syscall
push rax
 
mov rax, 54
mov rdi, qword [rsp]
mov rsi, sol_sock
mov rdx, reuse_addr
mov qword [rsp - 16], 1
lea r10, [rsp - 16]
mov r8, 4
syscall
 
mov rax, 54
mov rdi, qword [rsp]
mov rsi, sol_sock
mov rdx, reuse_port
mov qword [rsp - 16], 1
lea r10, [rsp - 16]
mov r8, 4
syscall
 
 
pop rax
ret
 
; rdi - socket
; rsi - port
; rdx - connections
; return - void
bind_and_listen:
 
push rdi
push rdx
 
mov rdi, rsi
call htn_swap16
 
lea rsi, [rsp - 16]
mov word [rsi + family_offset], af_inet
mov word [rsi + port_offset], ax
mov dword [rsi + addr_offset], addr_any
mov qword [rsi + unused_offset], 0
 
mov rax, 49
mov rdi, qword [rsp + 8]
mov rdx, addr_len
syscall
 
mov rax, 50
pop rsi
pop rdi
syscall
ret
 
; rdi - server socket
; return - client socket
accept:
 
mov rax, 43
lea rsi, [rsp - 16]
lea rdx, [rsp - 24]
syscall
ret
 
; rdi - client socket
; return - void
echo:
 
push rdi
mov rax, 0
lea rsi, [rsp - 104]
mov rdx, buffer_len
syscall
 
pop rdi
mov rdx, rax
lea rsi, [rsp - 112]
mov rax, 1
syscall
ret
 
 
_start:
 
call create_server_socket
mov r14, rax
 
mov rdi, rax
mov rsi, server_port
mov rdx, max_connections
call bind_and_listen
 
accept_connection:
 
mov rdi, r14
call accept
 
mov r15, rax
mov rax, 57
syscall
 
test rax, rax
jz handle_connection
 
; close client socket
mov rax, 3
mov rdi, r15
syscall
jmp accept_connection
handle_connection:
 
mov rdi, r15
call echo
 
close_client:
mov rax, 3
mov rdi, r15
syscall
 
close_server:
mov rax, 3
mov rdi, r14
syscall
 
exit:
mov rax, 60
xor rdi, rdi
syscall
</syntaxhighlight>
 
=={{header|Wren}}==
{{trans|C}}
An embedded program so we can ask the C host to call the relevant library functions for us and also handle simultaneous connections from multiple clients using a multi-process approach.
<syntaxhighlight lang="wren">/* Echo_server.wren */
 
var MAX_ENQUEUED = 20
var BUF_LEN = 256
var PORT_STR = "12321"
 
var AF_UNSPEC = 0
var SOCK_STREAM = 1
var AI_PASSIVE = 1
 
foreign class AddrInfo {
foreign static getAddrInfo(name, service, req, pai)
 
construct new() {}
 
foreign family
 
foreign family=(f)
 
foreign sockType
 
foreign sockType=(st)
 
foreign flags
 
foreign flags=(f)
 
foreign protocol
 
foreign addr
 
foreign addrLen
}
 
foreign class AddrInfoPtr {
construct new() {}
 
foreign deref
 
foreign free()
}
 
class Socket {
foreign static create(domain, type, protocol)
 
foreign static bind(fd, addr, len)
 
foreign static listen(fd, n)
 
foreign static accept(fd, addr, addrLen)
}
 
foreign class SockAddrPtr {
construct new() {}
 
foreign size
}
 
class SigAction {
foreign static cleanUpProcesses()
}
 
foreign class Buffer {
construct new(size) {}
}
 
class Posix {
foreign static read(fd, buf, nbytes)
 
foreign static write(fd, buf, n)
 
foreign static fork()
 
foreign static close(fd)
}
 
// Child process.
var echoLines = Fn.new { |csock|
var buf = Buffer.new(BUF_LEN)
var r
while ((r = Posix.read(csock, buf, BUF_LEN)) > 0) {
Posix.write(csock, buf, r)
}
}
 
// Parent process.
var takeConnectionsForever = Fn.new { |ssock|
while (true) {
var addr = SockAddrPtr.new()
var addrSize = addr.size
 
/* Block until we take one connection to the server socket */
var csock = Socket.accept(ssock, addr, addrSize)
 
/* If it was a successful connection, spawn a worker process to service it. */
if (csock == -1) {
System.print("Error accepting socket.")
} else if (Posix.fork() == 0) {
Posix.close(ssock)
echoLines.call(csock)
return
} else {
Posix.close(csock)
}
}
}
 
/* Look up the address to bind to. */
var hints = AddrInfo.new()
hints.family = AF_UNSPEC
hints.sockType = SOCK_STREAM
hints.flags = AI_PASSIVE
var addrInfoPtr = AddrInfoPtr.new()
if (AddrInfo.getAddrInfo("", PORT_STR, hints, addrInfoPtr) != 0) {
Fiber.abort("Failed to get pointer to addressinfo.")
}
 
/* Make a socket. */
var res = addrInfoPtr.deref
var sock = Socket.create(res.family, res.sockType, res.protocol)
if (sock == -1) Fiber.abort("Failed to make a socket.")
 
/* Arrange to clean up child processes (the workers). */
SigAction.cleanUpProcesses()
 
/* Associate the socket with its address. */
if (Socket.bind(sock, res.addr, res.addrLen) != 0) {
Fiber.abort("Failed to bind socket.")
}
 
addrInfoPtr.free()
 
/* State that we've opened a server socket and are listening for connections. */
if (Socket.listen(sock, MAX_ENQUEUED) != 0) {
Fiber.abort("Failed to listen for connections.")
}
 
/* Serve the listening socket until killed */
takeConnectionsForever.call(sock)</syntaxhighlight>
<br>
which we now embed in the following C program, build and run:
<syntaxhighlight lang="c">/* gcc Echo_server.c -o Echo_server -lwren -lm */
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include "wren.h"
 
/* Clean up dead processes. */
void wait_for_zombie(int s) {
while (waitpid(-1, NULL, WNOHANG) > 0) ;
}
 
/* C <=> Wren interface functions */
 
void C_addrInfoAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct addrinfo));
}
 
void C_addrInfoPtrAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct addrinfo*));
}
 
void C_sockAddrPtrAllocate(WrenVM* vm) {
wrenSetSlotNewForeign(vm, 0, 0, sizeof(struct sockaddr*));
}
 
void C_bufferAllocate(WrenVM* vm) {
size_t bufsize = (size_t)wrenGetSlotDouble(vm, 1);
wrenSetSlotNewForeign(vm, 0, 0, bufsize);
}
 
void C_getAddrInfo(WrenVM* vm) {
const char *name = wrenGetSlotString(vm, 1);
if (strcmp(name, "") == 0) name = NULL;
const char *service = wrenGetSlotString(vm, 2);
const struct addrinfo *req = (const struct addrinfo *)wrenGetSlotForeign(vm, 3);
struct addrinfo** ppai = (struct addrinfo**)wrenGetSlotForeign(vm, 4);
int status = getaddrinfo(name, service, req, ppai);
wrenSetSlotDouble(vm, 0, (double)status);
}
 
void C_family(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)(pai->ai_family));
}
 
void C_setFamily(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
int f = (int)wrenGetSlotDouble(vm, 1);
pai->ai_family = f;
}
 
void C_sockType(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)(pai->ai_socktype));
}
 
void C_setSockType(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
int type = (int)wrenGetSlotDouble(vm, 1);
pai->ai_socktype = type;
}
 
void C_flags(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)(pai->ai_flags));
}
 
void C_setFlags(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
int flags = (int)wrenGetSlotDouble(vm, 1);
pai->ai_flags = flags;
}
 
void C_protocol(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)(pai->ai_protocol));
}
 
void C_addr(WrenVM* vm) {
wrenEnsureSlots(vm, 2);
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
wrenGetVariable(vm, "main", "SockAddrPtr", 1);
struct sockaddr **ppsa = (struct sockaddr**)wrenSetSlotNewForeign(vm, 0, 1, sizeof(struct sockaddr*));
*ppsa = pai->ai_addr;
}
 
void C_addrLen(WrenVM* vm) {
struct addrinfo* pai = (struct addrinfo*)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)(pai->ai_addrlen));
}
 
void C_deref(WrenVM* vm) {
wrenEnsureSlots(vm, 2);
struct addrinfo** ppai = (struct addrinfo**)wrenGetSlotForeign(vm, 0);
wrenGetVariable(vm, "main", "AddrInfo", 1);
struct addrinfo *pai = (struct addrinfo*)wrenSetSlotNewForeign(vm, 0, 1, sizeof(struct addrinfo));
*pai = **ppai;
}
 
void C_free(WrenVM* vm) {
struct addrinfo* pai = *(struct addrinfo**)wrenGetSlotForeign(vm, 0);
freeaddrinfo(pai);
}
 
void C_create(WrenVM* vm) {
int domain = (int)wrenGetSlotDouble(vm, 1);
int type = (int)wrenGetSlotDouble(vm, 2);
int protocol = (int)wrenGetSlotDouble(vm, 3);
int fd = socket(domain, type, protocol);
wrenSetSlotDouble(vm, 0, (double)fd);
}
 
void C_bind(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
__CONST_SOCKADDR_ARG *psa = (__CONST_SOCKADDR_ARG *)wrenGetSlotForeign(vm, 2);
socklen_t len = (socklen_t)wrenGetSlotDouble(vm, 3);
int status = bind(fd, *psa, len);
wrenSetSlotDouble(vm, 0, (double)status);
}
 
void C_listen(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
int n = (int)wrenGetSlotDouble(vm, 2);
int status = listen(fd, n);
wrenSetSlotDouble(vm, 0, (double)status);
}
 
void C_accept(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
__SOCKADDR_ARG *psa = (__SOCKADDR_ARG *)wrenGetSlotForeign(vm, 2);
socklen_t len = (socklen_t)wrenGetSlotDouble(vm, 3);
int status = accept(fd, *psa, &len);
wrenSetSlotDouble(vm, 0, (double)status);
}
 
void C_size(WrenVM* vm) {
struct sockaddr** ppaddr = (struct sockaddr**)wrenGetSlotForeign(vm, 0);
wrenSetSlotDouble(vm, 0, (double)sizeof(**ppaddr));
}
 
void C_cleanUpProcesses(WrenVM* vm) {
struct sigaction sa;
sa.sa_handler = wait_for_zombie;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1 ) {
perror("sigaction");
exit(EXIT_FAILURE);
}
}
 
void C_read(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
void *buf = (void *)wrenGetSlotForeign(vm, 2);
size_t nbytes = (size_t)wrenGetSlotDouble(vm, 3);
ssize_t res = read(fd, buf, nbytes);
wrenSetSlotDouble(vm, 0, (double)res);
}
 
void C_write(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
void *buf = (void *)wrenGetSlotForeign(vm, 2);
size_t n = (size_t)wrenGetSlotDouble(vm, 3);
ssize_t res = write(fd, buf, n);
wrenSetSlotDouble(vm, 0, (double)res);
}
 
void C_fork(WrenVM* vm) {
__pid_t pid = fork();
wrenSetSlotDouble(vm, 0, (double)pid);
}
 
void C_close(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
int status = close(fd);
wrenSetSlotDouble(vm, 0, (double)status);
}
 
WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "AddrInfo") == 0) {
methods.allocate = C_addrInfoAllocate;
} else if (strcmp(className, "AddrInfoPtr") == 0) {
methods.allocate = C_addrInfoPtrAllocate;
} else if (strcmp(className, "SockAddrPtr") == 0) {
methods.allocate = C_sockAddrPtrAllocate;
} else if (strcmp(className, "Buffer") == 0) {
methods.allocate = C_bufferAllocate;
}
}
return methods;
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "AddrInfo") == 0) {
if ( isStatic && strcmp(signature, "getAddrInfo(_,_,_,_)") == 0) return C_getAddrInfo;
if (!isStatic && strcmp(signature, "family") == 0) return C_family;
if (!isStatic && strcmp(signature, "family=(_)") == 0) return C_setFamily;
if (!isStatic && strcmp(signature, "sockType") == 0) return C_sockType;
if (!isStatic && strcmp(signature, "sockType=(_)") == 0) return C_setSockType;
if (!isStatic && strcmp(signature, "flags") == 0) return C_flags;
if (!isStatic && strcmp(signature, "flags=(_)") == 0) return C_setFlags;
if (!isStatic && strcmp(signature, "protocol") == 0) return C_protocol;
if (!isStatic && strcmp(signature, "addr") == 0) return C_addr;
if (!isStatic && strcmp(signature, "addrLen") == 0) return C_addrLen;
} else if (strcmp(className, "AddrInfoPtr") == 0) {
if (!isStatic && strcmp(signature, "deref") == 0) return C_deref;
if (!isStatic && strcmp(signature, "free()") == 0) return C_free;
} else if (strcmp(className, "Socket") == 0) {
if ( isStatic && strcmp(signature, "create(_,_,_)") == 0) return C_create;
if ( isStatic && strcmp(signature, "bind(_,_,_)") == 0) return C_bind;
if ( isStatic && strcmp(signature, "listen(_,_)") == 0) return C_listen;
if ( isStatic && strcmp(signature, "accept(_,_,_)") == 0) return C_accept;
} else if (strcmp(className, "SockAddrPtr") == 0) {
if (!isStatic && strcmp(signature, "size") == 0) return C_size;
} else if (strcmp(className, "SigAction") == 0) {
if ( isStatic && strcmp(signature, "cleanUpProcesses()") == 0) return C_cleanUpProcesses;
} else if (strcmp(className, "Posix") == 0) {
if ( isStatic && strcmp(signature, "read(_,_,_)") == 0) return C_read;
if ( isStatic && strcmp(signature, "write(_,_,_)") == 0) return C_write;
if ( isStatic && strcmp(signature, "fork()") == 0) return C_fork;
if ( isStatic && strcmp(signature, "close(_)") == 0) return C_close;
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Echo_server.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</syntaxhighlight>
 
{{out}}
Quick test using 2 terminals and telnet as the client (also tested on 3 terminals - not shown here):
<pre>
/* start server on terminal 1 */
$ ./Echo_server
 
/* start telnet on terminal 2 and type 'hello' */
$ telnet localhost 12321
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
hello
^]
telnet> quit
Connection closed.
 
/* press ctrl-c on terminal 1 to kill the server */
^C
</pre>
 
=={{header|zkl}}==
<langsyntaxhighlight lang="zkl">const PORT=12321;
pipe:=Thread.Pipe(); // how server tells thread to connect to user
Line 2,101 ⟶ 3,055:
server:=Network.TCPServerSocket.open(PORT);
println("Listening on %s:%s".fmt(server.hostname,server.port));
server.listen(echo.launch); // Main event loop</langsyntaxhighlight>
{{out}}
The next three windows overlap in time
Line 2,138 ⟶ 3,092:
{{omit from|M4}}
{{omit from|Maxima}}
{{omit from|Minimal BASIC}}
{{omit from|ML/I}}
{{omit from|Palo Alto Tiny BASIC}}
{{omit from|PARI/GP}}
{{omit from|PL/0}}
{{omit from|Retro|No concurrency support}}
{{omit from|SNUSP|No networking.}}
{{omit from|Tiny BASIC}}
{{omit from|Unlambda|Does not have network access.}}
{{omit from|Commodore BASIC}}
9,476

edits