Echo server

From Rosetta Code
Revision as of 18:57, 18 October 2011 by rosettacode>Ledrug (→‎{{header|Common Lisp}}: making hidden category a banner)
Task
Echo server
You are encouraged to solve this task according to the task description, using any language you may know.

Create a network service that sits on TCP port 12321, which accepts connections on that port, and which echoes complete lines (using a carriage-return/line-feed sequence as line separator) back to clients. No error handling is required. For the purposes of testing, it is only necessary to support connections from localhost (127.0.0.1 or perhaps ::1). Logging of connection information to standard output is recommended.

The implementation must be able to handle simultaneous connections from multiple clients. A multi-threaded or multi-process solution may be used. Each connection must be able to echo more than a single line.

The implementation must not stop responding to other clients if one client sends a partial line or stops reading responses.

Ada

Works with: GNAT

single-threaded, one client served at a time.

<lang Ada>with Ada.Text_IO; with Ada.IO_Exceptions; with GNAT.Sockets; procedure Echo_Server is

  Receiver   : GNAT.Sockets.Socket_Type;
  Connection : GNAT.Sockets.Socket_Type;
  Client     : GNAT.Sockets.Sock_Addr_Type;
  Channel    : GNAT.Sockets.Stream_Access;

begin

  GNAT.Sockets.Create_Socket (Socket => Receiver);
  GNAT.Sockets.Set_Socket_Option
    (Socket => Receiver,
     Option => (Name    => GNAT.Sockets.Reuse_Address, Enabled => True));
  GNAT.Sockets.Bind_Socket
    (Socket  => Receiver,
     Address => (Family => GNAT.Sockets.Family_Inet,
                 Addr   => GNAT.Sockets.Inet_Addr ("127.0.0.1"),
                 Port   => 12321));
  GNAT.Sockets.Listen_Socket (Socket => Receiver);
  loop
     GNAT.Sockets.Accept_Socket
       (Server  => Receiver,
        Socket  => Connection,
        Address => Client);
     Ada.Text_IO.Put_Line
       ("Client connected from " & GNAT.Sockets.Image (Client));
     Channel := GNAT.Sockets.Stream (Connection);
     begin
        loop
           Character'Output (Channel, Character'Input (Channel));
        end loop;
     exception
        when Ada.IO_Exceptions.End_Error =>
           null;
     end;
     GNAT.Sockets.Close_Socket (Connection);
  end loop;

end Echo_Server;</lang>

AutoHotkey

echoserver.ahk, modified from script by zed gecko. <lang AutoHotkey>#SingleInstance Force Network_Port = 12321 Network_Address = 127.0.0.1

NewData := false DataReceived = Gosub Connection_Init return

Connection_Init: OnExit, ExitSub socket := PrepareForIncomingConnection(Network_Address, Network_Port) if socket = -1

   ExitApp

Process, Exist DetectHiddenWindows On ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " . ErrorLevel) DetectHiddenWindows Off

NotificationMsg = 0x5555 OnMessage(NotificationMsg, "ReceiveData")

ExitMsg = 0x6666 OnMessage(ExitMsg, "ExitData")

FD_READ = 1 FD_CLOSE = 32 FD_CONNECT = 20

if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket,

     "UInt", ScriptMainWindowId, "UInt", ExitMsg, "Int", FD_CLOSE)

{

   msgbox, closed

}

if DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket,

       "UInt", ScriptMainWindowId, "UInt", NotificationMsg, "Int",
       FD_READ|FD_CONNECT) 

{

   MsgBox % "WSAAsyncSelect() indicated Winsock error "
         . DllCall("Ws2_32\WSAGetLastError")
   DllCall("Ws2_32\WSAAsyncSelect", "UInt", socket, 
         "UInt", ScriptMainWindowId, "UInt", ExitMsg, "Int", FD_CLOSE)
   ExitApp

}

SetTimer, NewConnectionCheck, 500 return

PrepareForIncomingConnection(IPAddress, Port) {

   VarSetCapacity(wsaData, 32)
   result := DllCall("Ws2_32\WSAStartup", "UShort", 0x0002, "UInt", &wsaData)
   if ErrorLevel
   {
       MsgBox % "WSAStartup() could not be called due to error %ErrorLevel%. "
               . "Winsock 2.0 or higher is required."
       return -1
   }
   if result
   {
       MsgBox % "WSAStartup() indicated Winsock error "
               . DllCall("Ws2_32\WSAGetLastError")
       return -1
   }
   AF_INET = 2
   SOCK_STREAM = 1
   IPPROTO_TCP = 6
   socket := DllCall("Ws2_32\socket", "Int", AF_INET, 
         "Int", SOCK_STREAM, "Int", IPPROTO_TCP)
   if socket = -1
   {
       MsgBox % "socket() indicated Winsock error "
               . DllCall("Ws2_32\WSAGetLastError")
       return -1
   }
   SizeOfSocketAddress = 16
   VarSetCapacity(SocketAddress, SizeOfSocketAddress)
   InsertInteger(2, SocketAddress, 0, AF_INET)
   InsertInteger(DllCall("Ws2_32\htons", "UShort", Port), SocketAddress, 2, 2)
   InsertInteger(DllCall("Ws2_32\inet_addr", "Str", IPAddress),
           SocketAddress, 4, 4)
   if DllCall("Ws2_32\bind", "UInt", socket, 
           "UInt", &SocketAddress, "Int", SizeOfSocketAddress)
   {
       MsgBox % "bind() indicated Winsock error "
               . DllCall("Ws2_32\WSAGetLastError") . "?"
       return -1
   }
   if DllCall("Ws2_32\listen", "UInt", socket, "UInt", "SOMAXCONN")
   {
       MsgBox % "LISTEN() indicated Winsock error "
               . DllCall("Ws2_32\WSAGetLastError") . "?"
       return -1
   }
   return socket

}

ReceiveData(wParam, lParam) {

   global DataReceived
   global NewData
   global mydata
   global ConnectionList
   socket := wParam
   ReceivedDataSize = 4096
   Loop
   {
       VarSetCapacity(ReceivedData, ReceivedDataSize, 0)
       ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", 
             socket, "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)

if ReceivedDataLength = 0

       {   
           StringReplace, ConnectionList, ConnectionList, %socket%`n
           DllCall("Ws2_32\closesocket", "UInt", socket)
       } 
       if ReceivedDataLength = -1
       {
           WinsockError := DllCall("Ws2_32\WSAGetLastError")
           if WinsockError = 10035
           {
               DataReceived = %TempDataReceived%
               NewData := true
               return 1
           }
           if WinsockError <> 10054
           {
               MsgBox % "recv() indicated Winsock error " . WinsockError
               StringReplace, ConnectionList, ConnectionList, %socket%`n
               DllCall("Ws2_32\closesocket", "UInt", socket)
           }
       }
       mydata := ReceivedData
       gosub myreceive

if (A_Index = 1)

           TempDataReceived =
               TempDataReceived = %TempDataReceived%%ReceivedData%
   }
   return 1

}

ExitData(wParam, lParam) {

   global ConnectionList
   socket := wParam
   ReceivedDataSize = 16
   VarSetCapacity(ReceivedData, ReceivedDataSize, 0)
   ReceivedDataLength := DllCall("Ws2_32\recv", "UInt", socket, 
         "Str", ReceivedData, "Int", ReceivedDataSize, "Int", 0)
   StringReplace, ConnectionList, ConnectionList, %socket%`n
   DllCall("Ws2_32\closesocket", "UInt", socket)
   return 1

}

SendData(wParam,SendData) {

   SendDataSize := VarSetCapacity(SendData)
   SendDataSize += 1
   Loop, parse, wParam, `n
   {
       If A_LoopField =
          Continue
       socket := A_LoopField
       sendret := DllCall("Ws2_32\send", "UInt", socket, 
             "Str", SendData, "Int", SendDatasize, "Int", 0)
   }

}


InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4) {

   Loop %pSize%
       DllCall("RtlFillMemory", "UInt", &pDest + pOffset + A_Index-1, 
               "UInt", 1, "UChar", pInteger >> 8*(A_Index-1) & 0xFF)

}

NewConnectionCheck: ConnectionCheck := DllCall("Ws2_32\accept", "UInt", socket,

     "UInt", &SocketAddress, "Int", SizeOfSocketAddress)

if ConnectionCheck > 1

   ConnectionList = %ConnectionList%%ConnectionCheck%`n

Return

SendProcedure: If ConnectionList <> {

   SendText = %A_Hour%:%A_Min%:%A_Sec%
   SendData(ConnectionList,SendText)

} Return

myreceive:

TrayTip, server, %mydata%, ,16
 return

GuiClose: ExitSub: DllCall("Ws2_32\WSACleanup") ExitApp</lang> A client is also available for testing this code.

C

Works with: POSIX

This is a rather standard code (details apart); the reference guide for such a code is the Beej's Guide to Network programming. The dependency from POSIX is mainly in the use of the read and write functions, (using the socket as a file descriptor sometimes make things simpler).

<lang c>#include <stdio.h>

  1. include <stdlib.h>
  2. include <string.h>
  3. include <errno.h>
  4. include <sys/types.h>
  5. include <sys/socket.h>
  6. include <netdb.h>
  7. include <unistd.h>
  8. include <sys/wait.h>
  9. include <signal.h>
  1. define MAX_ENQUEUED 20
  2. define BUF_LEN 256
  3. define PORT_STR "12321"

/* ------------------------------------------------------------ */ /* How to clean up after dead child processes */ /* ------------------------------------------------------------ */

void wait_for_zombie(int s) {

   while(waitpid(-1, NULL, WNOHANG) > 0) ;

}

/* ------------------------------------------------------------ */ /* Core of implementation of a child process */ /* ------------------------------------------------------------ */

void echo_lines(int csock) {

   char buf[BUF_LEN];
   int r;
   while( (r = read(csock, buf, BUF_LEN)) > 0 ) {
       (void)write(csock, buf, r);
   }
   exit(EXIT_SUCCESS);

}

/* ------------------------------------------------------------ */ /* Core of implementation of the parent process */ /* ------------------------------------------------------------ */

void take_connections_forever(int ssock) {

   for(;;) {
       struct sockaddr addr;
       socklen_t addr_size = sizeof(addr);
       int csock;
       /* Block until we take one connection to the server socket */
       csock = accept(ssock, &addr, &addr_size);
       /* If it was a successful connection, spawn a worker process to service it */
       if ( csock == -1 ) {
           perror("accept");
       } else if ( fork() == 0 ) {
           close(ssock);
           echo_lines(csock);
       } else {
           close(csock);
       }
   }

}

/* ------------------------------------------------------------ */ /* The server process's one-off setup code */ /* ------------------------------------------------------------ */

int main() {

   struct addrinfo hints, *res;
   struct sigaction sa;
   int sock;
   /* Look up the address to bind to */
   memset(&hints, 0, sizeof(struct addrinfo));
   hints.ai_family = AF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags = AI_PASSIVE;
   if ( getaddrinfo(NULL, PORT_STR, &hints, &res) != 0 ) {
       perror("getaddrinfo");
       exit(EXIT_FAILURE);
   }
   /* Make a socket */
   if ( (sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1 ) {
       perror("socket");
       exit(EXIT_FAILURE);
   }
   /* Arrange to clean up child processes (the workers) */
   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);
   }
   /* Associate the socket with its address */
   if ( bind(sock, res->ai_addr, res->ai_addrlen) != 0 ) {
       perror("bind");
       exit(EXIT_FAILURE);
   }
   freeaddrinfo(res);
   /* State that we've opened a server socket and are listening for connections */
   if ( listen(sock, MAX_ENQUEUED) != 0 ) {
       perror("listen");
       exit(EXIT_FAILURE);
   }
   /* Serve the listening socket until killed */
   take_connections_forever(sock);
   return EXIT_SUCCESS;

}</lang>

C#

<lang csharp> using System.Net.Sockets; using System.Threading;

namespace ConsoleApplication1 {

   class Program
   {
       static TcpListener listen;
       static Thread serverthread;
       static void Main(string[] args)
       {
           listen = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"), 12321);
           serverthread = new Thread(new ThreadStart(DoListen));
           serverthread.Start();
       }
       private static void DoListen()
       {
           // Listen
           listen.Start();
           Console.WriteLine("Server: Started server");
           while (true)
           {
               Console.WriteLine("Server: Waiting...");
               TcpClient client = listen.AcceptTcpClient();
               Console.WriteLine("Server: Waited");
               // New thread with client
               Thread clientThread = new Thread(new ParameterizedThreadStart(DoClient));
               clientThread.Start(client);
           }
       }
       private static void DoClient(object client)
       {
           // Read data
           TcpClient tClient = (TcpClient)client;
           Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId);
           do
           {
               if (!tClient.Connected)
               { 
                   tClient.Close();
                   Thread.CurrentThread.Abort();       // Kill thread.
               }
               if (tClient.Available > 0)
               {
                   // Resend
                   byte pByte = (byte)tClient.GetStream().ReadByte();
                   Console.WriteLine("Client (Thread: {0}): Data {1}", Thread.CurrentThread.ManagedThreadId, pByte);
                   tClient.GetStream().WriteByte(pByte);
               }
               // Pause
               Thread.Sleep(100);
           } while (true);
       }
   }

} </lang>

Clojure

<lang lisp>(use '[clojure.contrib.server-socket :only (create-server)]) (use '[clojure.contrib.duck-streams :only (read-lines write-lines)])

(defn echo [input output]

 (write-lines (java.io.PrintWriter. output true) (read-lines input)))

(create-server 12321 echo)</lang>

Note here that an auto-flushing PrintWriter needs to be created, otherwise 'output' could simply be passed to write-lines.

Common Lisp

This example is in need of improvement:

There should be a http://common-lisp.net/project/usocket/ example.

Sockets is not a standard part of Common Lisp but many implementations have support for this. The following example

Works with: CLISP

<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.")

(defun echo-server (port)

   "Listen on `port' for new client connections and for data arriving on

any existing client connections"

   (let ((server (socket:socket-server port)))
       (format t "Echo service listening on port ~a:~d~%"
           (socket:socket-server-host server)
           (socket:socket-server-port server))
       (unwind-protect
           (loop 
               (when (socket:socket-status server 0 1)
                   (echo-accept-client (socket:socket-accept server 
                                           :external-format :dos
                                           :buffered t)))
               (when *clients*
                   (socket:socket-status *clients* 0 1)
                   (mapcar #'(lambda (client)
                                 (when (eq :input (cddr client))
                                     (echo-service-client (car client)))
                                 (when (eq :eof (cddr client))
                                     (echo-close-client (car client)))) *clients*)))
           (socket-server-close server))))

(defun echo-accept-client (socket)

   "Accept a new client connection and add it to the watch list."
   (multiple-value-bind 
       (host port) (socket:socket-stream-peer socket)
       (format t "Connect from ~a:~d~%" host port))
   (push (list socket :input nil) *clients*))
   

(defun echo-service-client (socket)

   (let ((line (read-line socket nil nil)))
       (princ line socket)
       (finish-output socket)))

(defun echo-close-client (socket)

   "Close a client connection and remove it from the watch list."
   (multiple-value-bind 
       (host port) (socket:socket-stream-peer socket)
       (format t "Closing connection from ~a:~d~%" host port))
   (close socket)
   (setq *clients* (remove socket *clients* :key #'car)))

(echo-server 12321)</lang>

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 currSock.receive() 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.

<lang d> // Tested using DMD 2.048 import std.socket; import std.array;

void main() {

   Socket listener = new TcpSocket;
   assert(listener.isAlive);
   listener.bind(new InternetAddress(12321));
   listener.listen(10);
   Socket currSock;
   uint bytesRead;
   ubyte buff[1];
   while(1)
   {
       currSock = listener.accept();
       while ((bytesRead = currSock.receive(buff)) > 0)
       {
           currSock.send(buff);
       }
       currSock.close();
       buff.clear();
   }

}</lang>

Delphi

<lang Delphi>program EchoServer;

{$APPTYPE CONSOLE}

uses SysUtils, IdContext, IdTCPServer;

type

 TEchoServer = class
 private
   FTCPServer: TIdTCPServer;
 public
   constructor Create;
   destructor Destroy; override;
   procedure TCPServerExecute(AContext: TIdContext);
 end;

constructor TEchoServer.Create; begin

 FTCPServer := TIdTCPServer.Create(nil);
 FTCPServer.DefaultPort := 12321;
 FTCPServer.OnExecute := TCPServerExecute;
 FTCPServer.Active := True;

end;

destructor TEchoServer.Destroy; begin

 FTCPServer.Active := False;
 FTCPServer.Free;
 inherited Destroy;

end;

procedure TEchoServer.TCPServerExecute(AContext: TIdContext); var

 lCmdLine: string;

begin

 lCmdLine := AContext.Connection.IOHandler.ReadLn;
 Writeln('>' + lCmdLine);
 AContext.Connection.IOHandler.Writeln('>' + lCmdLine);
 if SameText(lCmdLine, 'QUIT') then
 begin
   AContext.Connection.IOHandler.Writeln('Disconnecting');
   AContext.Connection.Disconnect;
 end;

end;

var

 lEchoServer: TEchoServer;

begin

 lEchoServer := TEchoServer.Create;
 try
   Writeln('Delphi Echo Server');
   Writeln('Press Enter to quit');
   Readln;
 finally
   lEchoServer.Free;
 end;

end.</lang>

Erlang

<lang erlang> -module(echo). -export([start/0]).

start() ->

   spawn(fun () -> {ok, Sock} = gen_tcp:listen(12321, [{packet, line}]),
                   echo_loop(Sock)
         end).

echo_loop(Sock) ->

   {ok, Conn} = gen_tcp:accept(Sock),
   io:format("Got connection: ~p~n", [Conn]),
   Handler = spawn(fun () -> handle(Conn) end),
   gen_tcp:controlling_process(Conn, Handler),
   echo_loop(Sock).

handle(Conn) ->

   receive
       {tcp, Conn, Data} ->
           gen_tcp:send(Conn, Data),
           handle(Conn);
       {tcp_closed, Conn} ->
           io:format("Connection closed: ~p~n", [Conn])
   end.

</lang>

F#

<lang fsharp>open System.IO open System.Net open System.Net.Sockets

let service (client:TcpClient) =

   use stream = client.GetStream()
   use out = new StreamWriter(stream, AutoFlush = true)
   use inp = new StreamReader(stream)
   while not inp.EndOfStream do
       match inp.ReadLine() with
       | line -> printfn "< %s" line
                 out.WriteLine(line)
   printfn "closed %A" client.Client.RemoteEndPoint
   client.Close |> ignore

let EchoService =

   let socket = new TcpListener(IPAddress.Loopback, 12321)
   do socket.Start()
   printfn "echo service listening on %A" socket.Server.LocalEndPoint
   while true do
       let client = socket.AcceptTcpClient()
       printfn "connect from %A" client.Client.RemoteEndPoint
       let job = async {
           use c = client in try service client with _ -> () }
       Async.Start job

[<EntryPoint>] let main _ =

   EchoService
   0

</lang>

Factor

Connections get logged to /place-where-factor-is/logs/echo-server. <lang factor>USING: accessors io io.encodings.utf8 io.servers.connection threads ; IN: rosetta.echo

CONSTANT: echo-port 12321

handle-client ( -- )
   [ write "\r\n" write flush ] each-line ;
<echo-server> ( -- threaded-server )
   utf8 <threaded-server>
       "echo-server" >>name
       echo-port >>insecure
       [ handle-client ] >>handler ;
start-echo-server ( -- threaded-server )
   <echo-server> [ start-server ] in-thread ;</lang>

Forth

Works with: GNU Forth version 0.7.0

<lang forth>include unix/socket.fs

128 constant size

(echo) ( sock buf -- sock buf )
 begin
   cr ." waiting..."
   2dup 2dup size read-socket nip
   dup 0>
 while
   ."  got: " 2dup type
   rot write-socket
 repeat
 drop drop drop ;

create buf size allot

echo-server ( port -- )
 cr ." Listening on " dup .
 create-server
 dup 4 listen
 begin
   dup accept-socket
   cr ." Connection!"
   buf ['] (echo) catch
   cr ." Disconnected (" . ." )"
   drop close-socket
 again ;

12321 echo-server</lang> TODO: use tasker.fs and non-blocking semantics to handle mutliple connections

Go

<lang go>package main

import ( "fmt" "net" "bufio" )

func echo(s net.Conn, i int) { fmt.Printf("%d: %v <-> %v\n", i, s.LocalAddr(), s.RemoteAddr()) b := bufio.NewReader(s) for { line, e := b.ReadBytes('\n') if e != nil { break } s.Write(line) } fmt.Printf("%d: closed\n", i) }

func main() { l, e := net.Listen("tcp", ":12321") for i := 0; e == nil; i++ { var s net.Conn s, e = l.Accept() go echo(s, i) } } </lang>

Haskell

<lang haskell>module Main where import Network (withSocketsDo, accept, listenOn, sClose, PortID(PortNumber)) import Control.Monad (forever) import System.IO (hGetLine, hPutStrLn, hFlush, hClose) import System.IO.Error (isEOFError) import Control.Concurrent (forkIO) import Control.Exception (bracket)

-- For convenience in testing, ensure that the listen socket is closed if the main loop is aborted withListenOn port body = bracket (listenOn port) sClose body

echo (handle, host, port) = catch (forever doOneLine) stop where

 doOneLine = do line <- hGetLine handle
                print (host, port, init line)
                hPutStrLn handle line
                hFlush handle
 stop error = do putStrLn $ "Closed connection from " ++ show (host, port) ++ " due to " ++ show error
                 hClose handle

main = withSocketsDo $

 withListenOn (PortNumber 12321) $ \listener ->
   forever $ do
     acc@(_, host, port) <- accept listener
     putStrLn $ "Accepted connection from " ++ show (host, port)
     forkIO (echo acc)</lang>

Java

<lang java>import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket;

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(); } }

class ClientHandler implements Runnable { private static int numConnections; private int connectionId = 0; Socket clientSocket;

public ClientHandler(Socket s) { connectionId = numConnections++; System.out.println("handling connection, #" + connectionId); clientSocket = s; }

public void run() { PrintWriter out = null; BufferedReader in = null; try { out = new PrintWriter(clientSocket.getOutputStream(), true); in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); String inputLine, outputLine; while((inputLine = in.readLine()) != null){ outputLine = inputLine; System.out.println("recieved: " + outputLine); out.write(outputLine+"\n"); out.flush(); if (outputLine.equals("exit")) break; } } catch(Exception e) { e.printStackTrace(); } finally { out.close(); try { in.close(); clientSocket.close(); System.out.println("closing connection, #" + connectionId); } catch (IOException e) { e.printStackTrace(); } } } }</lang>

JavaScript

Works with: Node.js

<lang javascript>var net = require('net');

var server = net.createServer(function(conn) {

 console.log("Connection from " + conn.remoteAddress + " on port " + conn.remotePort);
 conn.setEncoding("utf8");
 var buffer = "";
 conn.on("data", function(data) {
   for(var i = 0; i <= data.length; i++) {
     var char = data.charAt(i);
     buffer += char;
     if(char == "\n") {
       conn.write(buffer);
       buffer = "";
     }
   }
 });

});

server.listen(12321, "localhost");</lang>

Oz

<lang oz>declare

 ServerSocket = {New Open.socket init}
 proc {Echo Socket}
    case {Socket getS($)} of false then skip
    [] Line then
       {System.showInfo "Received line: "#Line}
       {Socket write(vs:Line#"\n")}
       {Echo Socket}
    end
 end
 class TextSocket from Open.socket Open.text end

in

 {ServerSocket bind(takePort:12321)}
 {System.showInfo "Socket bound."}
 {ServerSocket listen}
 {System.showInfo "Started listening."}
 for do
    ClientHost ClientPort
    ClientSocket = {ServerSocket accept(accepted:$

acceptClass:TextSocket host:?ClientHost port:?ClientPort )}

 in
    {System.showInfo "Connection accepted from "#ClientHost#":"#ClientPort#"."}
    thread
       {Echo ClientSocket}

{System.showInfo "Connection lost: "#ClientHost#":"#ClientPort#"."}

       {ClientSocket close}
    end
 end</lang>

Client test code: <lang oz>declare

 Socket = {New class $ from Open.socket Open.text end init}

in

 {Socket connect(port:12321)}
 {Socket write(vs:"Hello\n")}
 {System.showInfo "Client received: "#{Socket getS($)}}
 {Socket close}</lang>

Example session:

Socket bound.
Started listening.
Connection accepted from localhost:2048.
Received line: Hello
Client received: Hello
Connection lost: localhost:2048.

Perl

This server will run indefinitely listening in the port 12321 and forking every time a client connects, the childs listen to the client and write back.

This is an example using the IO::Socket module: <lang perl>use IO::Socket; my $use_fork = 1;

my $sock = new IO::Socket::INET (

                                LocalHost => '127.0.0.1',
                                LocalPort => '12321',
                                Proto => 'tcp',
                                Listen => 1,   # maximum queued connections
                                Reuse => 1,
                               )

or die "socket: $!"; # no newline, so perl appends stuff

$SIG{CHLD} = 'IGNORE' if $use_fork; # let perl deal with zombies

print "listening...\n"; while (1) { # declare $con 'my' so it's closed by parent every loop

       my $con = $sock->accept()

or die "accept: $!"; fork and next if $use_fork; # following are for child only

print "incoming..\n"; print $con $_ while(<$con>); # read each line and write back print "done\n";

last if $use_fork; # if not forking, loop }

  1. child will reach here and close its copy of $sock before exit</lang>

This is an equivalent program using the Net::Server module: <lang perl>package Echo; use base 'Net::Server::Fork'; sub process_request {

   print while <STDIN>;

} Echo->run(port => 12321, log_level => 3);</lang> It also prints the IP address and port number of every connection.

This is a more complicated example using preforking: <lang perl>package Echo; use base 'Net::Server::PreFork'; sub process_request {

   print while <STDIN>;

} Echo->run(port => 12321, log_level => 3);</lang> 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.

PHP

<lang PHP>$socket = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); socket_bind($socket, '127.0.0.1', 12321); socket_listen($socket);

$client_count = 0; while (true){

 if (($client = socket_accept($socket)) === false) continue;
 $client_count++;
 $client_name = 'Unknown';
 socket_getpeername($client, $client_name);
 echo "Client {$client_count} ({$client_name}) connected\n";
 $pid = pcntl_fork();
 if($pid == -1) die('Could not fork');
 if($pid){
   pcntl_waitpid(-1, $status, WNOHANG);
   continue;
 }
 //In a child process
 while(true){
   if($input = socket_read($client, 1024)){
     socket_write($client, $input);
   } else {
     socket_shutdown($client);
     socket_close($client);
     echo "Client {$client_count} ({$client_name}) disconnected\n";
     exit();
   }
 }

}</lang>

PicoLisp

<lang PicoLisp>(setq Port (port 12321))

(loop

  (setq Sock (listen Port))           # Listen
  (NIL (fork) (close Port))           # Accepted
  (close Sock) )                      # Parent: Close socket and continue
  1. Child:

(prinl (stamp) " -- (Pid " *Pid ") Client connected from " *Adr)

(in Sock

  (until (eof)                        # Echo lines
     (out Sock (prinl (line))) ) )

(prinl (stamp) " -- (Pid " *Pid ") Client disconnected") (bye) # Terminate child</lang>

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>

Python

Works with: Python version 2.3 or above

<lang python>import SocketServer

HOST = "localhost" PORT = 12321

  1. this server uses ThreadingMixIn - one thread per connection
  2. replace with ForkMixIn to spawn a new process per connection

class EchoServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):

   # no need to override anything - default behavior is just fine
   pass

class EchoRequestHandler(SocketServer.StreamRequestHandler):

   """
   Handles one connection to the client.
   """
   def handle(self):
       print "connection from %s" % self.client_address[0]
       while True:
           line = self.rfile.readline()
           if not line: break
           print "%s wrote: %s" % (self.client_address[0], line.rstrip())
           self.wfile.write(line)
       print "%s disconnected" % self.client_address[0]


  1. Create the server

server = EchoServer((HOST, PORT), EchoRequestHandler)

  1. Activate the server; this will keep running until you
  2. interrupt the program with Ctrl-C

print "server listening on %s:%s" % server.server_address server.serve_forever()</lang>

REBOL

<lang rebol>server-port: open/lines tcp://:12321 forever [

   connection-port: first server-port
   until [
       wait connection-port
       error? try [insert connection-port first connection-port]
   ]
   close connection-port

] close server-port</lang>

Ruby

<lang ruby>require 'socket' server = TCPServer.new(12321)

while (connection = server.accept)

 Thread.new(connection) do |conn|
   port, host = conn.peeraddr[1,2]
   client = "#{host}:#{port}"
   puts "#{client} is connected"
   begin
     loop do
       line = conn.readline
       puts "#{client} says: #{line}"
       conn.puts(line)
     end
   rescue EOFError
     conn.close
     puts "#{client} has disconnected"
   end
 end

end</lang>

Scheme

Works with: Guile

Based on the Guile Internet Socket Server Example. <lang scheme>; Needed in Guile for read-line (use-modules (ice-9 rdelim))

Variable used to hold child PID returned from forking

(define child #f)

Start listening on port 12321 for connections from any address

(let ((s (socket PF_INET SOCK_STREAM 0)))

 (setsockopt s SOL_SOCKET SO_REUSEADDR 1)
 (bind s AF_INET INADDR_ANY 12321)
 (listen s 5) ; Queue size of 5
 (simple-format #t "Listening for clients in pid: ~S" (getpid))
 (newline)
Wait for connections forever
 (while #t
   (let* ((client-connection (accept s))
       (client-details (cdr client-connection))
       (client (car client-connection)))
Once something connects fork
     (set! child (primitive-fork))
     (if (zero? child)
     (begin
Then have child fork to avoid zombie children (grandchildren aren't our responsibility)
       (set! child (primitive-fork))
       (if (zero? child)
         (begin
Display some connection details
         (simple-format #t "Got new client connection: ~S" client-details)
         (newline)
         (simple-format #t "Client address: ~S"
           (gethostbyaddr (sockaddr:addr client-details)))
         (newline)
Wait for input from client and then echo the input back forever (or until client quits)
         (do ((line (read-line client)(read-line client))) ((zero? 1))
           (display line client)(newline client))))
Child exits after spawning grandchild.
       (primitive-exit))
Parent waits for child to finish spawning grandchild
     (waitpid child)))))</lang>

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., select() 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.

<lang tcl># How to handle an incoming new connection proc acceptEcho {chan host port} {

   puts "opened connection from $host:$port"
   fconfigure $chan -blocking 0 -buffering line -translation crlf
   fileevent $chan readable [list echo $chan $host $port]

}

  1. How to handle an incoming message on a connection

proc echo {chan host port} {

   if {[gets $chan line] >= 0} {
       puts $chan $line
   } elseif {[eof $chan]} {
       close $chan
       puts "closed connection from $host:$port"
   }
   # Other conditions causing a short read need no action

}

  1. Make the server socket and wait for connections

socket -server acceptEcho -myaddr localhost 12321 vwait forever</lang>

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. <lang tcl># How to handle an incoming new connection proc acceptEcho {chan host port} {

   puts "opened connection from $host:$port"
   fconfigure $chan -translation binary -buffering none
   fcopy $chan $chan -command [list done $chan $host $port]

}

  1. Called to finalize the connection

proc done {chan host port args} {

   puts "closed connection from $host:$port"
   close $chan

}

  1. Make the server socket and wait for connections

socket -server acceptEcho -myaddr localhost 12321 vwait forever</lang>