Hello world/Web server: Difference between revisions
Added socket only version for D |
m →{{header|D}}: changed port to 8080 |
||
Line 145: | Line 145: | ||
import std.socket, std.array; |
import std.socket, std.array; |
||
ushort port = |
ushort port = 8080; |
||
void main() { |
void main() { |
Revision as of 10:27, 28 October 2012
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
The browser is the new GUI!
The task is to serve our standard text "Goodbye, World!" to http://localhost:8080/ so that it can be viewed with a web browser. The provided solution must start or implement a server that accepts multiple client connections and serves text as requested.
Note that starting a web browser or opening a new window with this URL is not part of the task. Additionally, it is permissible to serve the provided page as a plain text file (there is no requirement to serve properly formatted HTML here). The browser will generally do the right thing with simple text like this.
Ada
Uses many defaults, such as 5 max simultaneous connections. <lang ada> with AWS; use AWS; with AWS.Response; with AWS.Server; with AWS.Status; with Ada.Text_IO; use Ada.Text_IO; procedure HelloHTTP is
function CB (Request : Status.Data) return Response.Data is pragma Unreferenced (Request); begin return Response.Build ("text/html", "Hello world!"); end CB; TheServer : Server.HTTP; ch : Character;
begin
Server.Start (TheServer, "Rosettacode", Callback => CB'Unrestricted_Access, Port => 8080); Put_Line ("Press any key to quit."); Get_Immediate (ch); Server.Shutdown (TheServer);
end HelloHTTP; </lang>
AWK
With GNU AWK (gawk) a simple web server can be implemented. The example is taken from here [1] (Documentation is licensed under GNU Free Documentation License, Version 1.3) <lang AWK>#!/usr/bin/gawk -f
BEGIN { RS = ORS = "\r\n" HttpService = "/inet/tcp/8080/0/0" Hello = "<HTML><HEAD>" \ "<TITLE>A Famous Greeting</TITLE></HEAD>" \
"<BODY>
Hello, world
</BODY></HTML>"
Len = length(Hello) + length(ORS) print "HTTP/1.0 200 OK" |& HttpService print "Content-Length: " Len ORS |& HttpService print Hello |& HttpService while ((HttpService |& getline) > 0) continue; close(HttpService) }</lang>
C
This is, um, slightly longer than what other languages would be. <lang C>#include <stdio.h>
- include <stdlib.h>
- include <unistd.h>
- include <sys/types.h>
- include <sys/socket.h>
- include <netinet/in.h>
- include <netdb.h>
- include <arpa/inet.h>
- include <err.h>
char response[] = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html; charset=UTF-8\r\n\r\n" "<doctype !html><html><head><title>Bye-bye baby bye-bye</title>" "<style>body { background-color: #111 }" "h1 { font-size:4cm; text-align: center; color: black;" " text-shadow: 0 0 2mm red}</style></head>"
"<body>
Goodbye, world!
</body></html>\r\n";
int main() { int one = 1, client_fd; struct sockaddr_in svr_addr, cli_addr; socklen_t sin_len = sizeof(cli_addr);
int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) err(1, "can't open socket");
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
int port = 8080; svr_addr.sin_family = AF_INET; svr_addr.sin_addr.s_addr = INADDR_ANY; svr_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) { close(sock); err(1, "Can't bind"); }
listen(sock, 5); while (1) { client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len); printf("got connection\n");
if (client_fd == -1) { perror("Can't accept"); continue; }
write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/ close(client_fd); } }</lang>
C++
C version compiles as C++ (known for G++ on Linux)
C#
<lang CSharp>using System.Text; using System.Net.Sockets; using System.Net;
namespace WebServer {
class GoodByeWorld { static void Main(string[] args) { const string msg = "<html>\n<body>\nGoodbye, world!\n</body>\n</html>\n"; const int port = 8080; bool serverRunning = true;
TcpListener tcpListener = new TcpListener(IPAddress.Any, port); tcpListener.Start();
while (serverRunning) { Socket socketConnection = tcpListener.AcceptSocket(); byte[] bMsg = Encoding.ASCII.GetBytes(msg.ToCharArray(), 0, (int)msg.Length); socketConnection.Send(bMsg); socketConnection.Disconnect(true); } } }
}</lang>
D
Using sockets only, also shows use of heredoc syntax, std.array.replace, and casting to bool to satisfy the while conditional.
<lang D> import std.socket, std.array;
ushort port = 8080;
void main() { Socket listener = new TcpSocket; listener.bind(new InternetAddress(port)); listener.listen(10);
Socket currSock;
while(cast(bool)(currSock = listener.accept())) { currSock.sendTo(replace(q"EOF HTTP/1.1 200 OK Content-Type: text/html; charset=UTF-8
<html> <head><title>Hello, world!</title></head> <body>Hello, world!</body> </html> EOF", "\n", "\r\n")); currSock.close(); } } </lang>
Delphi
<lang Delphi>program HelloWorldWebServer;
{$APPTYPE CONSOLE}
uses SysUtils, IdContext, IdCustomHTTPServer, IdHTTPServer;
type
TWebServer = class private FHTTPServer: TIdHTTPServer; public constructor Create; destructor Destroy; override; procedure HTTPServerCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); end;
constructor TWebServer.Create; begin
FHTTPServer := TIdHTTPServer.Create(nil); FHTTPServer.DefaultPort := 8080; FHTTPServer.OnCommandGet := HTTPServerCommandGet; FHTTPServer.Active := True;
end;
destructor TWebServer.Destroy; begin
FHTTPServer.Active := False; FHTTPServer.Free; inherited Destroy;
end;
procedure TWebServer.HTTPServerCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
AResponseInfo.ContentText := 'Goodbye, World!';
end;
var
lWebServer: TWebServer;
begin
lWebServer := TWebServer.Create; try Writeln('Delphi Hello world/Web server '); Writeln('Press Enter to quit'); Readln; finally lWebServer.Free; end;
end.</lang>
Dylan.NET
<lang Dylan.NET> //compile with dylan.NET 11.2.9.6 or later!!
- refstdasm "mscorlib.dll"
- refstdasm "System.dll"
import System.Text import System.Net.Sockets import System.Net
assembly helloweb exe ver 1.1.0.0
namespace WebServer
class public auto ansi GoodByeWorld method public static void main(var args as string[]) var msg as string = c"<html>\n<body>\nGoodbye, world!\n</body>\n</html>\n" var port as integer = 8080 var serverRunning as boolean = true
var tcpListener as TcpListener = new TcpListener(IPAddress::Any, port) tcpListener::Start()
do while serverRunning var socketConnection as Socket = tcpListener::AcceptSocket() var bMsg as byte[] = Encoding::get_ASCII()::GetBytes(msg::ToCharArray(), 0, msg::get_Length()) socketConnection::Send(bMsg) socketConnection::Disconnect(true) end do end method end class
end namespace </lang>
Fantom
<lang fantom>using web using wisp
const class HelloMod : WebMod // provides the content {
override Void onGet () { res.headers["Content-Type"] = "text/plain; charset=utf-8" res.out.print ("Goodbye, World!") }
}
class HelloWeb {
Void main () { WispService // creates the web service { port = 8080 root = HelloMod() }.start
while (true) {} // stay running }
}</lang>
Go
<lang go>package main
import (
"fmt" "net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintln(w, "Goodbye, World!") }) if err := http.ListenAndServe(":8080", nil); err != nil { fmt.Println(err) }
}</lang>
Haskell
Lightweightly concurrent "hello world" web server using the conduit stack:
<lang haskell>{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Char8 () import Data.Conduit ( ($$), yield ) import Data.Conduit.Network ( ServerSettings(..), runTCPServer )
main :: IO () main = runTCPServer (ServerSettings 8080 "127.0.0.1") $ const (yield response $$)
where response = "HTTP/1.0 200 OK\nContent-Length: 16\n\nGoodbye, World!\n"</lang>
Or using only "standard" features (base, bytestring and network from the Haskell Platform):
<lang haskell>{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString.Char8 () import Network hiding ( accept ) import Network.Socket ( accept ) import Network.Socket.ByteString ( sendAll ) import Control.Monad ( forever ) import Control.Exception ( bracket, finally ) import Control.Concurrent ( forkIO )
main :: IO () main = bracket (listenOn $ PortNumber 8080) sClose loop where
loop s = forever $ forkIO . request . fst =<< accept s request c = sendAll c response `finally` sClose c response = "HTTP/1.0 200 OK\nContent-Length: 16\n\nGoodbye, World!\n"</lang>
Both works like this:
$ curl http://localhost:8080/ Goodbye, World! # httperf --port=8080 --num-conns=10000 Request rate: 4549.5 req/s (0.2 ms/req) # httperf --port=8080 --num-conns=10000 --num-calls=2 Request rate: 8202.5 req/s (0.1 ms/req) Errors: total 10000 client-timo 0 socket-timo 0 connrefused 0 connreset 10000
Comparing to nginx:
# httperf --num-conns=10000 Request rate: 3613.2 req/s (0.3 ms/req) # httperf --num-conns=10000 --num-calls=10 Request rate: 9952.6 req/s (0.1 ms/req) # httperf --num-conns=10000 --num-calls=100 Request rate: 12341.0 req/s (0.1 ms/req)
which serve without any errors.
J
If the desire is to use the browser as a gui, the easiest thing to do would be to download j7, edit the jhs script to start on port 8080, start jhs, visit http://127.0.0.1:8080/jijx then enter the text: <lang j>'Goodbye, World!'</lang> This will compute the desired result and display it (actually, it will be displayed twice since the original string will also be displayed). This would be even simpler if you could just use the default jhs port (65001)... Alternatively, a jhs form could be used (but this would not have the exact url structure specified).
However, if the desire is to implement the task exactly, any of approaches at j:JWebServer might be used.
For example, here is a web server which ignores the client's request and always returns Goodbye, World: <lang j>hello=: verb define
8080 hello y NB. try to use port 8080 by default
port=: x require 'socket' coinsert 'jsocket' sdclose ; sdcheck sdgetsockets server=: {. ; sdcheck sdsocket sdcheck sdbind server; AF_INET; ; port sdcheck sdlisten server, 1 while. 1 do. while. server e. ready=: >{. sdcheck sdselect (sdcheck sdgetsockets ),;;<1e3 do. sdcheck sdaccept server end. for_socket. ready do. request=: ; sdcheck sdrecv socket, 65536 0 sdcheck (socket responseFor request) sdsend socket, 0 sdcheck sdclose socket end. end.
)
responseFor=: dyad define
'HTTP/1.0 200 OK',CRLF,'Content-Type: text/plain',CRLF,CRLF,'Goodbye, World!',CRLF
)</lang> To deploy this server, once it has been defined, run <lang j>hello</lang> This version works because reasonable http requests fit in a single tcp packet. (And note that the server waits for one tcp packet before responding.) If parsing of the request is desired, one of the more complicated implementations at j:JWebServer should be used instead (but that's not really relevant for this task, except perhaps to require complete headers before responding, with broken browsers which send multiple tcp packets for the request).
Java
Multiple requests will be served in the order that they reach the server, with a queue size limit of 50 waiting requests imposed by default in the ServerSocket
class (may be changed by adding a second positive integer argument to the ServerSocket
constructor).
<lang java>import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class HelloWorld{ public static void main(String[] args) throws IOException{ ServerSocket listener = new ServerSocket(8080); while(true){ Socket sock = listener.accept(); new PrintWriter(sock.getOutputStream(), true). println("Goodbye, World!"); sock.close(); } } }</lang>
JavaScript
Using node.js:
<lang javascript>var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Goodbye, World!\n');
}).listen(8080, '127.0.0.1');</lang>
It scales:
$ curl http://localhost:8080/ Goodbye, World! # httperf --port=8080 --num-conns=10000 Request rate: 1813.1 req/s (0.6 ms/req) # httperf --port=8080 --num-conns=10000 --num-calls=10 Request rate: 4869.1 req/s (0.2 ms/req) # httperf --port=8080 --num-conns=10000 --num-calls=100 Request rate: 5689.0 req/s (0.2 ms/req)
with no errors.
Liberty BASIC
This is difficult, although possible, in Liberty BASIC, but it's close relative Run BASIC is designed for serving webpages easily. The task becomes simply .. <lang lb>print "hello world!" </lang>
NetRexx
<lang NetRexx>/* NetRexx */ options replace format comments java crossref symbols binary
class RHelloWorldWebServer public
properties public constant isTrue = boolean (1 == 1) isFalse = boolean (1 \== 1) greeting1 = "Goodbye, World!" greeting2 = - || 'HTTP/1.1 200 OK\r\n' - || 'Content-Type: text/html; charset=UTF-8\r\n\r\n' - || '<?xml version="1.0" encoding="UTF-8"?>\r\n' - || '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\r\n' - || '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\r\n' - || '<header>\r\n' - || '<title>Hello</title>\r\n' - || '<style type="text/css">body {font-family: sans-serif;}</style>\r\n' - || '</header>\r\n' - || '<body>\r\n' -
|| '
' || greeting1 || '
\r\n' -
|| '</body>\r\n' - || '</html>\r\n' - ||
properties static inheritable terminate = isFalse -- TODO: provide a less draconian means to terminate the listener loop
method main(args = String[]) public static signals IOException listener = ServerSocket(8080) loop label listener forever if terminate then leave listener sock = listener.accept() PrintWriter(sock.getOutputStream(), isTrue).println(greeting2) sock.close() end listener return
</lang>
Objeck
<lang objeck> use Net; use Concurrency;
bundle Default {
class GoodByeWorld { function : Main(args : String[]) ~ Nil { server := TCPSocketServer->New(8080); if(server->Listen(5)) { while(true) { client := server->Accept(); client->WriteString("<html>\n<body>\nGoodbye, world!\n</body>\n</html>\n"); client->Close(); }; }; server->Close(); } }
} </lang>
OCaml
This code is derived from this ocaml-unix documentation. <lang ocaml>let try_finalise f x finally y =
let res = try f x with e -> finally y; raise e in finally y; res
let rec restart_on_EINTR f x =
try f x with Unix.Unix_error (Unix.EINTR, _, _) -> restart_on_EINTR f x
let double_fork_treatment server service (client_descr, _ as client) =
let treat () = match Unix.fork () with | 0 -> if Unix.fork () <> 0 then exit 0; Unix.close server; service client; exit 0 | k -> ignore (restart_on_EINTR (Unix.waitpid []) k) in try_finalise treat () Unix.close client_descr
let install_tcp_server_socket addr =
let s = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in try Unix.bind s addr; Unix.listen s 10; s with e -> Unix.close s; raise e
let tcp_server treat_connection addr =
ignore (Sys.signal Sys.sigpipe Sys.Signal_ignore); let server_sock = install_tcp_server_socket addr in while true do let client = restart_on_EINTR Unix.accept server_sock in treat_connection server_sock client done
let server () =
let port = 8080 in let host = (Unix.gethostbyname (Unix.gethostname())).Unix.h_addr_list.(0) in let addr = Unix.ADDR_INET (host, port) in let treat sock (client_sock, client_addr as client) = let service (s, _) = let response = "\ HTTP/1.1 200 OK\r\n\ Content-Type: text/html; charset=UTF-8\r\n\r\n\ <html><head><title>Goodbye, world!</title>\ <style>body { background-color: #0FF }\ h1 { font-size:3em; color: black; }</style></head>\
<body>
Goodbye, world!
</body></html>\r\n"
in Unix.write s response 0 (String.length response); in double_fork_treatment sock service client in tcp_server treat addr
let _ =
Unix.handle_unix_error server ()</lang>
Opa
From Opa documentation: <lang ocaml>server = one_page_server("Hello", -> <>Goodbye, world</>)</lang> Compile and run: <lang bash>opa file.opa --</lang>
Perl
<lang Perl>use Socket;
my $port = 8080; my $protocol = getprotobyname( "tcp" );
socket( SOCK, PF_INET, SOCK_STREAM, $protocol ) or die "couldn't open a socket: $!";
# PF_INET to indicate that this socket will connect to the internet domain # SOCK_STREAM indicates a TCP stream, SOCK_DGRAM would indicate UDP communication
setsockopt( SOCK, SOL_SOCKET, SO_REUSEADDR, 1 ) or die "couldn't set socket options: $!";
# SOL_SOCKET to indicate that we are setting an option on the socket instead of the protocol # mark the socket reusable
bind( SOCK, sockaddr_in($port, INADDR_ANY) ) or die "couldn't bind socket to port $port: $!";
# bind our socket to $port, allowing any IP to connect
listen( SOCK, SOMAXCONN ) or die "couldn't listen to port $port: $!";
# start listening for incoming connections
while( accept(CLIENT, SOCK) ){
print CLIENT "HTTP/1.1 200 OK\r\n" . "Content-Type: text/html; charset=UTF-8\r\n\r\n" . "<html><head><title>Goodbye, world!</title></head><body>Goodbye, world!</body></html>\r\n"; close CLIENT;
}</lang> Various modules exist for using sockets, including the popular IO::Socket which provides a simpler and more friendly OO interface for the socket layer. Here is the solution using this module:
<lang Perl>use IO::Socket::INET;
my $sock = new IO::Socket::INET ( LocalHost => "127.0.0.1",
LocalPort => "8080", Proto => "tcp", Listen => 1, Reuse => 1, ) or die "Could not create socket: $!";
while( my $client = $sock->accept() ){
print $client "HTTP/1.1 200 OK\r\n" . "Content-Type: text/html; charset=UTF-8\r\n\r\n" . "<html><head><title>Goodbye, world!</title></head><body>Goodbye, world!</body></html>\r\n"; close $client;
}</lang> Using Perl's glue power, provide a suicide note with visitor counter via netcat: <lang Perl>while (++(our $vn)) { open NC, "|-", qw(nc -l -p 8080 -q 1); print NC "HTTP/1.0 200 OK\xd\xa", "Content-type: text/plain; charset=utf-8\xd\xa\xd\xa", "Goodbye, World! (hello, visitor No. $vn!)\xd\xa"; }</lang>
Perl 6
<lang perl6>my $sock = IO::Socket::INET.new(:localhost('0.0.0.0'), :localport(8080), :listen); say "Goodbye Web Server listening on $sock.localhost():$sock.localport()"; while $sock.accept -> $client {
$client.send: "HTTP/1.0 200 OK\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\nGoodbye, World!\r\n"; $client.close;
}</lang>
PicoLisp
Contents of the file "goodbye.l": <lang PicoLisp>(html 0 "Bye" NIL NIL
"Goodbye, World!" )</lang>
Start server:
$ pil @lib/http.l @lib/xhtml.l -'server 8080 "goodbye.l"' -wait
PureBasic
<lang PureBasic>If InitNetwork() = 0 MessageRequester("Error", "Can't initialize the network !") End EndIf
Port = 8080
If CreateNetworkServer(0, Port) Repeat Delay(1) SEvent = NetworkServerEvent() If SEvent ClientID = EventClient() Select SEvent Case #PB_NetworkEvent_Data SendNetworkData(ClientID,@"Goodbye, World!",Len("Goodbye, World!")) CloseNetworkConnection(ClientID) EndSelect EndIf ForEver Else MessageRequester("Error", "Can't create the server (port in use ?).") EndIf</lang>
PHP
<lang PHP><?php
// AF_INET6 for IPv6 // IP
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die('Failed to create socket!');
// '127.0.0.1' to limit only to localhost // Port
socket_bind($socket, 0, 8080); socket_listen($socket);
$msg = '<html><head><title>Goodbye, world!</title></head><body>Goodbye, world!</body></html>';
for (;;) {
// @ is used to stop PHP from spamming with error messages if there is no connection if ($client = @socket_accept($socket)) { socket_write($client, "HTTP/1.1 200 OK\r\n" . "Content-length: " . strlen($msg) . "\r\n" . "Content-Type: text/html; charset=UTF-8\r\n\r\n" . $msg); } else usleep(100000); // limits CPU usage by sleeping after doing every request
}</lang>
Python
<lang Python>def app(environ, start_response):
start_response('200 OK', []) yield "Goodbye, World!"
if __name__ == '__main__':
from wsgiref.simple_server import make_server server = make_server('127.0.0.1', 8080, app) server.serve_forever()</lang>
Ruby
Using the WEBrick module from Ruby's standard library. <lang ruby>require 'webrick' server = WEBrick::HTTPServer.new(:Port => 8080) server.mount_proc('/') {|request, response| response.body = "Goodbye, World!"} trap("INT") {server.shutdown} server.start</lang> Using the sinatra gem: <lang ruby>require 'sinatra' get("/") { "Goodbye, World!" }</lang>
Run BASIC
<lang runbasic>html "Hello World!"</lang>
Salmon
<lang Salmon>use "http.salm" : "http.si";
/* Don't do any logging. */ procedure log(...) { };
simple_http_server(8080, procedure(header, connection)
{ respond_text(connection, "Goodbye, World!"); });</lang>
Tcl
This version is adapted from the Tcler's Wiki. <lang tcl>proc accept {chan addr port} {
while {[gets $chan] ne ""} {} puts $chan "HTTP/1.1 200 OK\nConnection: close\nContent-Type: text/plain\n" puts $chan "Goodbye, World!" close $chan
} socket -server accept 8080 vwait forever</lang>
- Programming Tasks
- Networking and Web Interaction
- Ada
- AWS
- AWK
- C
- C++
- C sharp
- D
- Delphi
- Dylan.NET
- Fantom
- Go
- Haskell
- J
- Java
- JavaScript
- Liberty BASIC
- NetRexx
- Objeck
- OCaml
- Opa
- Perl
- Perl 6
- PicoLisp
- PureBasic
- PHP
- Python
- Ruby
- Run BASIC
- Salmon
- Tcl
- GUISS/Omit
- Locomotive Basic/Omit
- Lotus 123 Macro Scripting/Omit
- ML/I/Omit
- ZX Spectrum Basic/Omit
- Retro/Omit
- Maxima/Omit