Chat server: Difference between revisions
Content added Content deleted
(Added Wren) |
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
||
Line 10: | Line 10: | ||
{{libheader|AdaSockets}} |
{{libheader|AdaSockets}} |
||
< |
<syntaxhighlight lang=Ada>with Ada.Containers.Vectors; |
||
with Ada.Command_Line; use Ada.Command_Line; |
with Ada.Command_Line; use Ada.Command_Line; |
||
with Ada.Exceptions; use Ada.Exceptions; |
with Ada.Exceptions; use Ada.Exceptions; |
||
Line 94: | Line 94: | ||
Dummy.Start (Incoming_Socket); |
Dummy.Start (Incoming_Socket); |
||
end loop; |
end loop; |
||
end Chat_Server;</ |
end Chat_Server;</syntaxhighlight> |
||
=={{header|BaCon}}== |
=={{header|BaCon}}== |
||
Requires BaCon 4.2 or higher. Clients have to login with an alias and can use the commands 'say' or 'quit'. Notifications are submitted when users enter the chat or leave the chat. |
Requires BaCon 4.2 or higher. Clients have to login with an alias and can use the commands 'say' or 'quit'. Notifications are submitted when users enter the chat or leave the chat. |
||
<lang>DECLARE user$ ASSOC STRING |
<syntaxhighlight lang=text>DECLARE user$ ASSOC STRING |
||
DECLARE connect ASSOC long |
DECLARE connect ASSOC long |
||
OPEN "localhost:51000" FOR SERVER AS mynet |
OPEN "localhost:51000" FOR SERVER AS mynet |
||
Line 132: | Line 132: | ||
ENDIF |
ENDIF |
||
ENDIF |
ENDIF |
||
WEND</ |
WEND</syntaxhighlight> |
||
=={{header|C}}== |
=={{header|C}}== |
||
Line 141: | Line 141: | ||
A glitch occurs if a connection is made using the Telnet protocol - user names are preceded by garbled text. |
A glitch occurs if a connection is made using the Telnet protocol - user names are preceded by garbled text. |
||
< |
<syntaxhighlight lang=c>#include <stdio.h> |
||
#include <stdlib.h> |
#include <stdlib.h> |
||
#include <sys/socket.h> |
#include <sys/socket.h> |
||
Line 388: | Line 388: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
< |
<syntaxhighlight lang=csharp>using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
using System.Net.Sockets; |
using System.Net.Sockets; |
||
Line 534: | Line 534: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|CoffeeScript}}== |
=={{header|CoffeeScript}}== |
||
This is ported from the JavaScript version. The tool js2coffee got me a mostly working version, and then I manually converted JS-style classes to CS "classic-style class" syntax. |
This is ported from the JavaScript version. The tool js2coffee got me a mostly working version, and then I manually converted JS-style classes to CS "classic-style class" syntax. |
||
< |
<syntaxhighlight lang=coffeescript> |
||
net = require("net") |
net = require("net") |
||
sys = require("sys") |
sys = require("sys") |
||
Line 647: | Line 647: | ||
server = new ChatServer() |
server = new ChatServer() |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
<syntaxhighlight lang=d> |
|||
<lang d> |
|||
import std.getopt; |
import std.getopt; |
||
import std.socket; |
import std.socket; |
||
Line 810: | Line 810: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 835: | Line 835: | ||
*USER-MANAGER*, or upon an error occurring. |
*USER-MANAGER*, or upon an error occurring. |
||
< |
<syntaxhighlight lang=common-lisp> |
||
(ql:quickload '(:usocket :simple-actors :bordeaux-threads)) |
(ql:quickload '(:usocket :simple-actors :bordeaux-threads)) |
||
Line 1,011: | Line 1,011: | ||
(make-thread #'accept-connections) |
(make-thread #'accept-connections) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Erlang}}== |
=={{header|Erlang}}== |
||
< |
<syntaxhighlight lang=erlang> |
||
-module(chat). |
-module(chat). |
||
Line 1,078: | Line 1,078: | ||
Response -> Response |
Response -> Response |
||
end. |
end. |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
Line 1,087: | Line 1,087: | ||
This example handles the case of one specific client "falling behind" by relying on the underlying TCP stack to do a reasonable job of buffering. Once that buffer fills, a write to the that client's connection will time out and the connection will dropped. Other minor improvements would include enabling TCP keep alives, handling temporary errors from accept, and better logging. Not ideal, but it should be good enough for this example. |
This example handles the case of one specific client "falling behind" by relying on the underlying TCP stack to do a reasonable job of buffering. Once that buffer fills, a write to the that client's connection will time out and the connection will dropped. Other minor improvements would include enabling TCP keep alives, handling temporary errors from accept, and better logging. Not ideal, but it should be good enough for this example. |
||
< |
<syntaxhighlight lang=go>package main |
||
import ( |
import ( |
||
Line 1,268: | Line 1,268: | ||
} |
} |
||
c.server.rem <- c.name |
c.server.rem <- c.name |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
{{trans|Java}} |
{{trans|Java}} |
||
< |
<syntaxhighlight lang=groovy>class ChatServer implements Runnable { |
||
private int port = 0 |
private int port = 0 |
||
private List<Client> clientList = new ArrayList<>() |
private List<Client> clientList = new ArrayList<>() |
||
Line 1,427: | Line 1,427: | ||
new ChatServer(port).run() |
new ChatServer(port).run() |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang=haskell>{-# LANGUAGE OverloadedStrings #-} |
||
import Network |
import Network |
||
import System.IO |
import System.IO |
||
Line 1,514: | Line 1,514: | ||
T.putStrLn "Server started" |
T.putStrLn "Server started" |
||
newMVar (M.empty) >>= clientLoop server |
newMVar (M.empty) >>= clientLoop server |
||
</syntaxhighlight> |
|||
</lang> |
|||
==Icon and {{header|Unicon}}== |
==Icon and {{header|Unicon}}== |
||
This is Unicon-specific: |
This is Unicon-specific: |
||
< |
<syntaxhighlight lang=unicon>global mlck, nCons, cons |
||
procedure main() |
procedure main() |
||
Line 1,545: | Line 1,545: | ||
critical mlck: nCons -:= 1 |
critical mlck: nCons -:= 1 |
||
} |
} |
||
end</ |
end</syntaxhighlight> |
||
=={{header|Java}}== |
=={{header|Java}}== |
||
Line 1,553: | Line 1,553: | ||
I think ideally, NIO would be used to select() sockets available/ready for I/O, to eliminate the possibility of a bad connection disrupting the server, but this increases the complexity. |
I think ideally, NIO would be used to select() sockets available/ready for I/O, to eliminate the possibility of a bad connection disrupting the server, but this increases the complexity. |
||
< |
<syntaxhighlight lang=java>import java.io.*; |
||
import java.net.*; |
import java.net.*; |
||
import java.util.*; |
import java.util.*; |
||
Line 1,705: | Line 1,705: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
{{works with|Node.js}} |
{{works with|Node.js}} |
||
< |
<syntaxhighlight lang=javascript>const net = require("net"); |
||
const EventEmitter = require("events").EventEmitter; |
const EventEmitter = require("events").EventEmitter; |
||
Line 1,856: | Line 1,856: | ||
// Start the server! |
// Start the server! |
||
server = new ChatServer();</ |
server = new ChatServer();</syntaxhighlight> |
||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
Modified to fit the Rosetta Code task from example code for the WebSockets module written by Leah Hanson. |
Modified to fit the Rosetta Code task from example code for the WebSockets module written by Leah Hanson. |
||
To test, start the code and use a browser to connect to localhost:8000. |
To test, start the code and use a browser to connect to localhost:8000. |
||
< |
<syntaxhighlight lang=julia> |
||
using HttpServer |
using HttpServer |
||
using WebSockets |
using WebSockets |
||
Line 1,944: | Line 1,944: | ||
println("Chat server listening on 8000...") |
println("Chat server listening on 8000...") |
||
run(server,8000) |
run(server,8000) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
{{trans|Java}} |
{{trans|Java}} |
||
< |
<syntaxhighlight lang=scala>import java.io.BufferedReader |
||
import java.io.IOException |
import java.io.IOException |
||
import java.io.InputStreamReader |
import java.io.InputStreamReader |
||
Line 2,100: | Line 2,100: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang=nim>import asyncnet, asyncdispatch |
||
type |
type |
||
Line 2,144: | Line 2,144: | ||
asyncCheck serve() |
asyncCheck serve() |
||
runForever()</ |
runForever()</syntaxhighlight> |
||
=={{header|Objeck}}== |
=={{header|Objeck}}== |
||
< |
<syntaxhighlight lang=objeck> |
||
use System.IO.Net; |
use System.IO.Net; |
||
use System.Concurrency; |
use System.Concurrency; |
||
Line 2,257: | Line 2,257: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Ol}}== |
=={{header|Ol}}== |
||
< |
<syntaxhighlight lang=scheme> |
||
(define (timestamp) (syscall 201 "%c")) |
(define (timestamp) (syscall 201 "%c")) |
||
Line 2,329: | Line 2,329: | ||
(run 8080) |
(run 8080) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
Line 2,387: | Line 2,387: | ||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang=perl>use 5.010; |
||
use strict; |
use strict; |
||
use warnings; |
use warnings; |
||
Line 2,494: | Line 2,494: | ||
sleep(0.1); |
sleep(0.1); |
||
}</ |
}</syntaxhighlight> |
||
===Alternate with both read and write queuing=== |
===Alternate with both read and write queuing=== |
||
< |
<syntaxhighlight lang=perl>#!/usr/bin/perl |
||
use strict; # http://www.rosettacode.org/wiki/Chat_server |
use strict; # http://www.rosettacode.org/wiki/Chat_server |
||
Line 2,575: | Line 2,575: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
===server=== |
===server=== |
||
<!--< |
<!--<syntaxhighlight lang=Phix>(notonline)--> |
||
<span style="color: #000080;font-style:italic;">-- |
<span style="color: #000080;font-style:italic;">-- |
||
-- demo\rosetta\ChatServer.exw |
-- demo\rosetta\ChatServer.exw |
||
Line 2,749: | Line 2,749: | ||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
===client=== |
===client=== |
||
<!--< |
<!--<syntaxhighlight lang=Phix>(notonline)--> |
||
<span style="color: #000080;font-style:italic;">-- |
<span style="color: #000080;font-style:italic;">-- |
||
-- demo\rosetta\ChatClient.exw |
-- demo\rosetta\ChatClient.exw |
||
Line 2,993: | Line 2,993: | ||
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span> |
||
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span> |
||
<!--</ |
<!--</syntaxhighlight>--> |
||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
< |
<syntaxhighlight lang=PicoLisp>#!/usr/bin/picolisp /usr/lib/picolisp/lib.l |
||
(de chat Lst |
(de chat Lst |
||
Line 3,023: | Line 3,023: | ||
(tell 'chat "--- " *Name " left ---") |
(tell 'chat "--- " *Name " left ---") |
||
(bye) ) ) ) |
(bye) ) ) ) |
||
(wait)</ |
(wait)</syntaxhighlight> |
||
After starting the above script, connect to the chat server from two terminals: |
After starting the above script, connect to the chat server from two terminals: |
||
<pre> Terminal 1 | Terminal 2 |
<pre> Terminal 1 | Terminal 2 |
||
Line 3,060: | Line 3,060: | ||
This version will load the server automatically on port 5000, adapt to your needs. |
This version will load the server automatically on port 5000, adapt to your needs. |
||
< |
<syntaxhighlight lang=prolog>:- initialization chat_server(5000). |
||
chat_server(Port) :- |
chat_server(Port) :- |
||
Line 3,140: | Line 3,140: | ||
msg_username_taken('That username is already taken, choose another\n\r'). |
msg_username_taken('That username is already taken, choose another\n\r'). |
||
msg_new_line('\n\r'). |
msg_new_line('\n\r'). |
||
msg_by_user('~w> ~w').</ |
msg_by_user('~w> ~w').</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
< |
<syntaxhighlight lang=python>#!/usr/bin/env python |
||
import socket |
import socket |
||
Line 3,220: | Line 3,220: | ||
time.sleep(.1) |
time.sleep(.1) |
||
except (SystemExit, KeyboardInterrupt): |
except (SystemExit, KeyboardInterrupt): |
||
break</ |
break</syntaxhighlight> |
||
=={{header|R}}== |
=={{header|R}}== |
||
This implementation relies on the new server socket connection type introduced in R 4.0.0. |
This implementation relies on the new server socket connection type introduced in R 4.0.0. |
||
<syntaxhighlight lang=R> |
|||
<lang R> |
|||
chat_loop <- function(server, sockets, delay = 0.5) { |
chat_loop <- function(server, sockets, delay = 0.5) { |
||
repeat { |
repeat { |
||
Line 3,370: | Line 3,370: | ||
} |
} |
||
start_chat_server()</ |
start_chat_server()</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
Line 3,376: | Line 3,376: | ||
This is a very basic chat server, but it does everything that is needed for this task. |
This is a very basic chat server, but it does everything that is needed for this task. |
||
< |
<syntaxhighlight lang=racket> |
||
#lang racket |
#lang racket |
||
Line 3,398: | Line 3,398: | ||
(void (thread (λ() (chat-server (tcp-listen 12321))))) |
(void (thread (λ() (chat-server (tcp-listen 12321))))) |
||
((client (current-input-port) (current-output-port))) |
((client (current-input-port) (current-output-port))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
Line 3,405: | Line 3,405: | ||
<div style="display:inline-block">{{trans|Python}}</div> (or at least started out that way) |
<div style="display:inline-block">{{trans|Python}}</div> (or at least started out that way) |
||
{{works with|Rakudo|2016.07}} |
{{works with|Rakudo|2016.07}} |
||
<lang |
<syntaxhighlight lang=raku line>react { |
||
my %connections; |
my %connections; |
||
Line 3,447: | Line 3,447: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Notes: |
Notes: |
||
Line 3,455: | Line 3,455: | ||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang=Ruby>require 'gserver' |
||
class ChatServer < GServer |
class ChatServer < GServer |
||
Line 3,523: | Line 3,523: | ||
#Turn on informational messages |
#Turn on informational messages |
||
ChatServer.new(7000, '0.0.0.0', 100, $stderr, true).start.join |
ChatServer.new(7000, '0.0.0.0', 100, $stderr, true).start.join |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
< |
<syntaxhighlight lang=rust> |
||
use std::collections::HashMap; |
use std::collections::HashMap; |
||
use std::io; |
use std::io; |
||
Line 3,623: | Line 3,623: | ||
chat_loop(&listener).unwrap(); |
chat_loop(&listener).unwrap(); |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
{{works with|Tcl|8.6}} |
{{works with|Tcl|8.6}} |
||
< |
<syntaxhighlight lang=tcl>package require Tcl 8.6 |
||
# Write a message to everyone except the sender of the message |
# Write a message to everyone except the sender of the message |
||
Line 3,687: | Line 3,687: | ||
socket -server {coroutine c[incr count] chat} 4004 |
socket -server {coroutine c[incr count] chat} 4004 |
||
set ::cmap {}; # Dictionary mapping nicks to channels |
set ::cmap {}; # Dictionary mapping nicks to channels |
||
vwait forever; # Run event loop</ |
vwait forever; # Run event loop</syntaxhighlight> |
||
=={{header|Visual Basic .NET}}== |
=={{header|Visual Basic .NET}}== |
||
{{trans|C#}} |
{{trans|C#}} |
||
< |
<syntaxhighlight lang=vbnet>Imports System.Net.Sockets |
||
Imports System.Text |
Imports System.Text |
||
Imports System.Threading |
Imports System.Threading |
||
Line 3,824: | Line 3,824: | ||
End Sub |
End Sub |
||
End Module</ |
End Module</syntaxhighlight> |
||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
Line 3,832: | Line 3,832: | ||
As Wren's VM is single threaded we create separate VMs to service each potential client connection (limited to 10) which run in their own thread. As the only way for the VMs to share mutable state is to use global variables within the host, synchronization is needed when accessing such variables. |
As Wren's VM is single threaded we create separate VMs to service each potential client connection (limited to 10) which run in their own thread. As the only way for the VMs to share mutable state is to use global variables within the host, synchronization is needed when accessing such variables. |
||
< |
<syntaxhighlight lang=ecmascript>/* chat_server.wren */ |
||
class Clients { |
class Clients { |
||
Line 4,030: | Line 4,030: | ||
foreign static read(connfd, count) |
foreign static read(connfd, count) |
||
foreign static close(connfd) |
foreign static close(connfd) |
||
}</ |
}</syntaxhighlight> |
||
<br> |
<br> |
||
We now embed this in the following C program, build and run it to start the server. To end the server, just press control-C. For testing purposes, clients can use telnet from separate terminals to connect to the server on port 5000. |
We now embed this in the following C program, build and run it to start the server. To end the server, just press control-C. For testing purposes, clients can use telnet from separate terminals to connect to the server on port 5000. |
||
< |
<syntaxhighlight lang=c>/* gcc chat_server.c -o chat_server -lpthread -lwren -lm */ |
||
#include <sys/socket.h> |
#include <sys/socket.h> |
||
Line 4,385: | Line 4,385: | ||
return 0; |
return 0; |
||
}</ |
}</syntaxhighlight> |
||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
{{trans|Python}} |
{{trans|Python}} |
||
On my Linux box, telnet seems to only want to connect to port 23. |
On my Linux box, telnet seems to only want to connect to port 23. |
||
< |
<syntaxhighlight lang=zkl>const PORT=23; |
||
var users=Dictionary(); // ( handle:socket, ...) |
var users=Dictionary(); // ( handle:socket, ...) |
||
Line 4,438: | Line 4,438: | ||
server:=Network.TCPServerSocket.open(PORT); |
server:=Network.TCPServerSocket.open(PORT); |
||
println("Listening on %s:%s".fmt(server.hostname,server.port)); |
println("Listening on %s:%s".fmt(server.hostname,server.port)); |
||
server.listen(pipe); // Main event loop </ |
server.listen(pipe); // Main event loop </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Start the server: |
Start the server: |