Chat server: Difference between revisions

Content added Content deleted
m (syntax highlighting fixup automation)
m (Automated syntax highlighting fixup (second round - minor fixes))
Line 6: Line 6:
People should be able to connect via ‘telnet’, sign on with a nickname, and type messages which will then be seen by all other connected users. Arrivals and departures of chat members should generate appropriate notification messages.
People should be able to connect via ‘telnet’, sign on with a nickname, and type messages which will then be seen by all other connected users. Arrivals and departures of chat members should generate appropriate notification messages.
<br><br>
<br><br>

=={{header|Ada}}==
=={{header|Ada}}==
{{libheader|AdaSockets}}
{{libheader|AdaSockets}}


<syntaxhighlight lang=Ada>with Ada.Containers.Vectors;
<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 95: Line 94:
end loop;
end loop;
end Chat_Server;</syntaxhighlight>
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.
<syntaxhighlight lang=text>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 133: Line 131:
ENDIF
ENDIF
WEND</syntaxhighlight>
WEND</syntaxhighlight>

=={{header|C}}==
=={{header|C}}==
C has no built-in networking functions, but the POSIX library does provide some low-level networking functions. The functions of interest relating to sockets include ''bind'', ''listen'', ''select'', ''accept'', ''read'', ''write'' and ''close''.
C has no built-in networking functions, but the POSIX library does provide some low-level networking functions. The functions of interest relating to sockets include ''bind'', ''listen'', ''select'', ''accept'', ''read'', ''write'' and ''close''.
Line 141: Line 138:
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>
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/socket.h>
Line 389: Line 386:
return 0;
return 0;
}</syntaxhighlight>
}</syntaxhighlight>

=={{header|C sharp|C#}}==
=={{header|C sharp|C#}}==
<syntaxhighlight lang=csharp>using System;
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Net.Sockets;
Line 535: Line 531:
}
}
}</syntaxhighlight>
}</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>
<syntaxhighlight lang="coffeescript">
net = require("net")
net = require("net")
sys = require("sys")
sys = require("sys")
Line 648: Line 643:
server = new ChatServer()
server = new ChatServer()
</syntaxhighlight>
</syntaxhighlight>

=={{header|D}}==
<syntaxhighlight lang=d>
import std.getopt;
import std.socket;
import std.stdio;
import std.string;

struct client {
int pos;
char[] name;
char[] buffer;
Socket socket;
}

void broadcast(client[] connections, size_t self, const char[] message) {
writeln(message);
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;

connections[i].socket.send(message);
connections[i].socket.send("\r\n");
}
}

bool registerClient(client[] connections, size_t self) {
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;

if (icmp(connections[i].name, connections[self].name) == 0) {
return false;
}
}

return true;
}

void main(string[] args) {
ushort port = 4004;

auto helpInformation = getopt
(
args,
"port|p", "The port to listen to chat clients on [default is 4004]", &port
);

if (helpInformation.helpWanted) {
defaultGetoptPrinter("A simple chat server based on a task in rosettacode.", helpInformation.options);
return;
}

auto listener = new TcpSocket();
assert(listener.isAlive);
listener.blocking = false;
listener.bind(new InternetAddress(port));
listener.listen(10);
writeln("Listening on port: ", port);

enum MAX_CONNECTIONS = 60;
auto socketSet = new SocketSet(MAX_CONNECTIONS + 1);
client[] connections;

while(true) {
socketSet.add(listener);

foreach (con; connections) {
socketSet.add(con.socket);
}

Socket.select(socketSet, null, null);

for (size_t i = 0; i < connections.length; i++) {
if (socketSet.isSet(connections[i].socket)) {
char[1024] buf;
auto datLength = connections[i].socket.receive(buf[]);

if (datLength == Socket.ERROR) {
writeln("Connection error.");
} else if (datLength != 0) {
if (buf[0] == '\n' || buf[0] == '\r') {
if (connections[i].buffer == "/quit") {
connections[i].socket.close();
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}

connections[i] = connections[$-1];
connections.length--;
i--;

writeln("\tTotal connections: ", connections.length);
continue;
} else if (connections[i].name.length == 0) {
connections[i].buffer = strip(connections[i].buffer);
if (connections[i].buffer.length > 0) {
connections[i].name = connections[i].buffer;
if (registerClient(connections, i)) {
connections.broadcast(i, "+++ " ~ connections[i].name ~ " arrived +++");
} else {
connections[i].socket.send("Name already registered. Please enter your name: ");
connections[i].name.length = 0;
}
} else {
connections[i].socket.send("A name is required. Please enter your name: ");
}
} else {
connections.broadcast(i, connections[i].name ~ "> " ~ connections[i].buffer);
}
connections[i].buffer.length = 0;
} else {
connections[i].buffer ~= buf[0..datLength];
}
} else {
try {
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}
} catch (SocketException) {
writeln("Connection closed.");
}
}
}
}

if (socketSet.isSet(listener)) {
Socket sn = null;
scope(failure) {
writeln("Error accepting");

if (sn) {
sn.close();
}
}
sn = listener.accept();
assert(sn.isAlive);
assert(listener.isAlive);

if (connections.length < MAX_CONNECTIONS) {
client newclient;

writeln("Connection from ", sn.remoteAddress(), " established.");
sn.send("Enter name: ");

newclient.socket = sn;
connections ~= newclient;

writeln("\tTotal connections: ", connections.length);
} else {
writeln("Rejected connection from ", sn.remoteAddress(), "; too many connections.");
sn.close();
assert(!sn.isAlive);
assert(listener.isAlive);
}
}

socketSet.reset();
}
}
</syntaxhighlight>

=={{header|Common Lisp}}==
=={{header|Common Lisp}}==
{{libheader|usocket}}
{{libheader|usocket}}
Line 835: Line 666:
*USER-MANAGER*, or upon an error occurring.
*USER-MANAGER*, or upon an error occurring.


<syntaxhighlight lang=common-lisp>
<syntaxhighlight lang="common-lisp">
(ql:quickload '(:usocket :simple-actors :bordeaux-threads))
(ql:quickload '(:usocket :simple-actors :bordeaux-threads))


Line 1,012: Line 843:
(make-thread #'accept-connections)
(make-thread #'accept-connections)
</syntaxhighlight>
</syntaxhighlight>
=={{header|D}}==
<syntaxhighlight lang="d">
import std.getopt;
import std.socket;
import std.stdio;
import std.string;


struct client {
int pos;
char[] name;
char[] buffer;
Socket socket;
}

void broadcast(client[] connections, size_t self, const char[] message) {
writeln(message);
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;

connections[i].socket.send(message);
connections[i].socket.send("\r\n");
}
}

bool registerClient(client[] connections, size_t self) {
for (size_t i = 0; i < connections.length; i++) {
if (i == self) continue;

if (icmp(connections[i].name, connections[self].name) == 0) {
return false;
}
}

return true;
}

void main(string[] args) {
ushort port = 4004;

auto helpInformation = getopt
(
args,
"port|p", "The port to listen to chat clients on [default is 4004]", &port
);

if (helpInformation.helpWanted) {
defaultGetoptPrinter("A simple chat server based on a task in rosettacode.", helpInformation.options);
return;
}

auto listener = new TcpSocket();
assert(listener.isAlive);
listener.blocking = false;
listener.bind(new InternetAddress(port));
listener.listen(10);
writeln("Listening on port: ", port);

enum MAX_CONNECTIONS = 60;
auto socketSet = new SocketSet(MAX_CONNECTIONS + 1);
client[] connections;

while(true) {
socketSet.add(listener);

foreach (con; connections) {
socketSet.add(con.socket);
}

Socket.select(socketSet, null, null);

for (size_t i = 0; i < connections.length; i++) {
if (socketSet.isSet(connections[i].socket)) {
char[1024] buf;
auto datLength = connections[i].socket.receive(buf[]);

if (datLength == Socket.ERROR) {
writeln("Connection error.");
} else if (datLength != 0) {
if (buf[0] == '\n' || buf[0] == '\r') {
if (connections[i].buffer == "/quit") {
connections[i].socket.close();
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}

connections[i] = connections[$-1];
connections.length--;
i--;

writeln("\tTotal connections: ", connections.length);
continue;
} else if (connections[i].name.length == 0) {
connections[i].buffer = strip(connections[i].buffer);
if (connections[i].buffer.length > 0) {
connections[i].name = connections[i].buffer;
if (registerClient(connections, i)) {
connections.broadcast(i, "+++ " ~ connections[i].name ~ " arrived +++");
} else {
connections[i].socket.send("Name already registered. Please enter your name: ");
connections[i].name.length = 0;
}
} else {
connections[i].socket.send("A name is required. Please enter your name: ");
}
} else {
connections.broadcast(i, connections[i].name ~ "> " ~ connections[i].buffer);
}
connections[i].buffer.length = 0;
} else {
connections[i].buffer ~= buf[0..datLength];
}
} else {
try {
if (connections[i].name.length > 0) {
writeln("Connection from ", connections[i].name, " closed.");
} else {
writeln("Connection from ", connections[i].socket.remoteAddress(), " closed.");
}
} catch (SocketException) {
writeln("Connection closed.");
}
}
}
}

if (socketSet.isSet(listener)) {
Socket sn = null;
scope(failure) {
writeln("Error accepting");

if (sn) {
sn.close();
}
}
sn = listener.accept();
assert(sn.isAlive);
assert(listener.isAlive);

if (connections.length < MAX_CONNECTIONS) {
client newclient;

writeln("Connection from ", sn.remoteAddress(), " established.");
sn.send("Enter name: ");

newclient.socket = sn;
connections ~= newclient;

writeln("\tTotal connections: ", connections.length);
} else {
writeln("Rejected connection from ", sn.remoteAddress(), "; too many connections.");
sn.close();
assert(!sn.isAlive);
assert(listener.isAlive);
}
}

socketSet.reset();
}
}
</syntaxhighlight>
=={{header|Erlang}}==
=={{header|Erlang}}==
<syntaxhighlight lang=erlang>
<syntaxhighlight lang="erlang">
-module(chat).
-module(chat).


Line 1,079: Line 1,071:
end.
end.
</syntaxhighlight>
</syntaxhighlight>

=={{header|Go}}==
=={{header|Go}}==
This example uses the Go idiom of [http://blog.golang.org/share-memory-by-communicating ''Do not communicate by sharing memory; instead, share memory by communicating'']; there are no explicit locks used, instead Go channels are used to safely synchronize where required.
This example uses the Go idiom of [http://blog.golang.org/share-memory-by-communicating ''Do not communicate by sharing memory; instead, share memory by communicating'']; there are no explicit locks used, instead Go channels are used to safely synchronize where required.
Line 1,087: Line 1,078:
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
<syntaxhighlight lang="go">package main


import (
import (
Line 1,269: Line 1,260:
c.server.rem <- c.name
c.server.rem <- c.name
}</syntaxhighlight>
}</syntaxhighlight>

=={{header|Groovy}}==
=={{header|Groovy}}==
{{trans|Java}}
{{trans|Java}}
<syntaxhighlight lang=groovy>class ChatServer implements Runnable {
<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,428: Line 1,418:
}
}
}</syntaxhighlight>
}</syntaxhighlight>

=={{header|Haskell}}==
=={{header|Haskell}}==
<syntaxhighlight lang=haskell>{-# LANGUAGE OverloadedStrings #-}
<syntaxhighlight lang="haskell">{-# LANGUAGE OverloadedStrings #-}
import Network
import Network
import System.IO
import System.IO
Line 1,519: Line 1,508:


This is Unicon-specific:
This is Unicon-specific:
<syntaxhighlight lang=unicon>global mlck, nCons, cons
<syntaxhighlight lang="unicon">global mlck, nCons, cons


procedure main()
procedure main()
Line 1,546: Line 1,535:
}
}
end</syntaxhighlight>
end</syntaxhighlight>

=={{header|Java}}==
=={{header|Java}}==


Line 1,553: Line 1,541:
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.*;
<syntaxhighlight lang="java">import java.io.*;
import java.net.*;
import java.net.*;
import java.util.*;
import java.util.*;
Line 1,706: Line 1,694:
}
}
</syntaxhighlight>
</syntaxhighlight>

=={{header|JavaScript}}==
=={{header|JavaScript}}==
{{works with|Node.js}}
{{works with|Node.js}}
<syntaxhighlight lang=javascript>const net = require("net");
<syntaxhighlight lang="javascript">const net = require("net");
const EventEmitter = require("events").EventEmitter;
const EventEmitter = require("events").EventEmitter;
Line 1,857: Line 1,844:
// Start the server!
// Start the server!
server = new ChatServer();</syntaxhighlight>
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>
<syntaxhighlight lang="julia">
using HttpServer
using HttpServer
using WebSockets
using WebSockets
Line 1,945: Line 1,931:
run(server,8000)
run(server,8000)
</syntaxhighlight>
</syntaxhighlight>

=={{header|Kotlin}}==
=={{header|Kotlin}}==
{{trans|Java}}
{{trans|Java}}
<syntaxhighlight lang=scala>import java.io.BufferedReader
<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,101: Line 2,086:
}
}
}</syntaxhighlight>
}</syntaxhighlight>

=={{header|Nim}}==
=={{header|Nim}}==
<syntaxhighlight lang=nim>import asyncnet, asyncdispatch
<syntaxhighlight lang="nim">import asyncnet, asyncdispatch


type
type
Line 2,145: Line 2,129:
asyncCheck serve()
asyncCheck serve()
runForever()</syntaxhighlight>
runForever()</syntaxhighlight>

=={{header|Objeck}}==
=={{header|Objeck}}==
<syntaxhighlight lang=objeck>
<syntaxhighlight lang="objeck">
use System.IO.Net;
use System.IO.Net;
use System.Concurrency;
use System.Concurrency;
Line 2,258: Line 2,241:
}
}
</syntaxhighlight>
</syntaxhighlight>

=={{header|Ol}}==
=={{header|Ol}}==
<syntaxhighlight lang=scheme>
<syntaxhighlight lang="scheme">
(define (timestamp) (syscall 201 "%c"))
(define (timestamp) (syscall 201 "%c"))


Line 2,384: Line 2,366:
(127.0.0.1 . 55320): see you..
(127.0.0.1 . 55320): see you..
</pre>
</pre>

=={{header|Perl}}==
=={{header|Perl}}==
{{trans|Python}}
{{trans|Python}}
<syntaxhighlight lang=perl>use 5.010;
<syntaxhighlight lang="perl">use 5.010;
use strict;
use strict;
use warnings;
use warnings;
Line 2,496: Line 2,477:
}</syntaxhighlight>
}</syntaxhighlight>
===Alternate with both read and write queuing===
===Alternate with both read and write queuing===
<syntaxhighlight lang=perl>#!/usr/bin/perl
<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,576: Line 2,557:
}
}
}</syntaxhighlight>
}</syntaxhighlight>

=={{header|Phix}}==
=={{header|Phix}}==
===server===
===server===
<!--<syntaxhighlight lang=Phix>(notonline)-->
<!--<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,751: Line 2,731:
<!--</syntaxhighlight>-->
<!--</syntaxhighlight>-->
===client===
===client===
<!--<syntaxhighlight lang=Phix>(notonline)-->
<!--<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,994: Line 2,974:
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
<!--</syntaxhighlight>-->

=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
<syntaxhighlight lang=PicoLisp>#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
<syntaxhighlight lang="picolisp">#!/usr/bin/picolisp /usr/lib/picolisp/lib.l


(de chat Lst
(de chat Lst
Line 3,055: Line 3,034:
| Connection closed.
| Connection closed.
| $</pre>
| $</pre>

=={{header|Prolog}}==
=={{header|Prolog}}==
Works with Swi-Prolog as of Jan 2019.
Works with Swi-Prolog as of Jan 2019.


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).
<syntaxhighlight lang="prolog">:- initialization chat_server(5000).


chat_server(Port) :-
chat_server(Port) :-
Line 3,141: Line 3,119:
msg_new_line('\n\r').
msg_new_line('\n\r').
msg_by_user('~w> ~w').</syntaxhighlight>
msg_by_user('~w> ~w').</syntaxhighlight>

=={{header|Python}}==
=={{header|Python}}==
<syntaxhighlight lang=python>#!/usr/bin/env python
<syntaxhighlight lang="python">#!/usr/bin/env python


import socket
import socket
Line 3,221: Line 3,198:
except (SystemExit, KeyboardInterrupt):
except (SystemExit, KeyboardInterrupt):
break</syntaxhighlight>
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>
<syntaxhighlight lang="r">
chat_loop <- function(server, sockets, delay = 0.5) {
chat_loop <- function(server, sockets, delay = 0.5) {
repeat {
repeat {
Line 3,371: Line 3,347:


start_chat_server()</syntaxhighlight>
start_chat_server()</syntaxhighlight>

=={{header|Racket}}==
=={{header|Racket}}==


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>
<syntaxhighlight lang="racket">
#lang racket
#lang racket


Line 3,399: Line 3,374:
((client (current-input-port) (current-output-port)))
((client (current-input-port) (current-output-port)))
</syntaxhighlight>
</syntaxhighlight>

=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
(formerly Perl 6)
Line 3,405: Line 3,379:
<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}}
<syntaxhighlight lang=raku line>react {
<syntaxhighlight lang="raku" line>react {
my %connections;
my %connections;
Line 3,453: Line 3,427:
* It accepts messages encoded in UTF-8.
* It accepts messages encoded in UTF-8.
* It tokenizes the message streams at newline boundaries (using the <tt>Supply.lines</tt> method), which I think makes the most sense for a chat application.
* It tokenizes the message streams at newline boundaries (using the <tt>Supply.lines</tt> method), which I think makes the most sense for a chat application.

=={{header|Ruby}}==
=={{header|Ruby}}==
<syntaxhighlight lang=Ruby>require 'gserver'
<syntaxhighlight lang="ruby">require 'gserver'


class ChatServer < GServer
class ChatServer < GServer
Line 3,524: Line 3,497:
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>
</syntaxhighlight>

=={{header|Rust}}==
=={{header|Rust}}==
<syntaxhighlight lang=rust>
<syntaxhighlight lang="rust">
use std::collections::HashMap;
use std::collections::HashMap;
use std::io;
use std::io;
Line 3,624: Line 3,596:
}
}
</syntaxhighlight>
</syntaxhighlight>

=={{header|Tcl}}==
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
{{works with|Tcl|8.6}}
<syntaxhighlight lang=tcl>package require 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,688: Line 3,659:
set ::cmap {}; # Dictionary mapping nicks to channels
set ::cmap {}; # Dictionary mapping nicks to channels
vwait forever; # Run event loop</syntaxhighlight>
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
<syntaxhighlight lang="vbnet">Imports System.Net.Sockets
Imports System.Text
Imports System.Text
Imports System.Threading
Imports System.Threading
Line 3,825: Line 3,795:


End Module</syntaxhighlight>
End Module</syntaxhighlight>

=={{header|Wren}}==
=={{header|Wren}}==
An embedded solution using a C host since Wren has no built in support for either networking or multi-threading.
An embedded solution using a C host since Wren has no built in support for either networking or multi-threading.
Line 3,832: Line 3,801:


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 */
<syntaxhighlight lang="ecmascript">/* chat_server.wren */


class Clients {
class Clients {
Line 4,033: Line 4,002:
<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 */
<syntaxhighlight lang="c">/* gcc chat_server.c -o chat_server -lpthread -lwren -lm */


#include <sys/socket.h>
#include <sys/socket.h>
Line 4,386: Line 4,355:
return 0;
return 0;
}</syntaxhighlight>
}</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;
<syntaxhighlight lang="zkl">const PORT=23;
var users=Dictionary(); // ( handle:socket, ...)
var users=Dictionary(); // ( handle:socket, ...)
Line 4,481: Line 4,449:
Connection closed by foreign host.
Connection closed by foreign host.
</pre>
</pre>

{{omit from|AutoHotkey}}
{{omit from|AutoHotkey}}
{{omit from|Lilypond}}
{{omit from|Lilypond}}
{{omit from|ML/I}}
{{omit from|Mathematica}}
{{omit from|Mathematica}}
{{omit from|Maxima}}
{{omit from|Maxima}}
{{omit from|ML/I}}
{{omit from|PARI/GP|No good way to access network}}
{{omit from|PARI/GP|No good way to access network}}
{{omit from|Retro}}
{{omit from|Retro}}