Chat server: Difference between revisions

m
m (syntax highlighting fixup automation)
m (→‎{{header|Wren}}: Minor tidy)
 
(2 intermediate revisions by 2 users not shown)
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.
<br><br>
 
=={{header|Ada}}==
{{libheader|AdaSockets}}
 
<syntaxhighlight lang=Ada"ada">with Ada.Containers.Vectors;
with Ada.Command_Line; use Ada.Command_Line;
with Ada.Exceptions; use Ada.Exceptions;
Line 96 ⟶ 95:
end Chat_Server;</syntaxhighlight>
 
=={{header|BaConBASIC}}==
==={{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.
<syntaxhighlight lang="text">DECLARE user$ ASSOC STRING
DECLARE connect ASSOC long
OPEN "localhost:51000" FOR SERVER AS mynet
Line 133:
ENDIF
WEND</syntaxhighlight>
 
==={{header|Visual Basic .NET}}===
{{trans|C#}}
<syntaxhighlight lang="vbnet">Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
 
Module Module1
 
Class State
Private ReadOnly client As TcpClient
Private ReadOnly sb As New StringBuilder
 
Public Sub New(name As String, client As TcpClient)
Me.Name = name
Me.client = client
End Sub
 
Public ReadOnly Property Name As String
 
Public Sub Send(text As String)
Dim bytes = Encoding.ASCII.GetBytes(String.Format("{0}" & vbCrLf, text))
client.GetStream().Write(bytes, 0, bytes.Length)
End Sub
End Class
 
ReadOnly connections As New Dictionary(Of Integer, State)
Dim listen As TcpListener
Dim serverThread As Thread
 
Sub Main()
listen = New TcpListener(Net.IPAddress.Parse("127.0.0.1"), 4004)
serverThread = New Thread(New ThreadStart(AddressOf DoListen))
serverThread.Start()
End Sub
 
Private Sub DoListen()
listen.Start()
Console.WriteLine("Server: Started server")
 
Do
Console.Write("Server: Waiting...")
Dim client = listen.AcceptTcpClient()
Console.WriteLine(" Connected")
 
' New thread with client
Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf DoClient))
 
clientThread.Start(client)
Loop
End Sub
 
Private Sub DoClient(client As TcpClient)
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId)
Dim bytes = Encoding.ASCII.GetBytes("Enter name: ")
client.GetStream().Write(bytes, 0, bytes.Length)
 
Dim done As Boolean
Dim name As String
Do
If Not client.Connected Then
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close()
Thread.CurrentThread.Abort() ' Kill thread
End If
 
name = Receive(client)
done = True
 
For Each cl In connections
Dim state = cl.Value
If state.Name = name Then
bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ")
client.GetStream().Write(bytes, 0, bytes.Length)
done = False
End If
Next
Loop While Not done
 
connections.Add(Thread.CurrentThread.ManagedThreadId, New State(name, client))
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Broadcast(String.Format("+++ {0} arrived +++", name))
 
Do
Dim text = Receive(client)
If text = "/quit" Then
Broadcast(String.Format("Connection from {0} closed.", name))
connections.Remove(Thread.CurrentThread.ManagedThreadId)
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Exit Do
End If
 
If Not client.Connected Then
Exit Do
End If
 
Broadcast(String.Format("{0}> {1}", name, text))
Loop
 
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close()
Thread.CurrentThread.Abort()
End Sub
 
Private Function Receive(client As TcpClient) As String
Dim sb As New StringBuilder
Do
If client.Available > 0 Then
While client.Available > 0
Dim ch = Chr(client.GetStream.ReadByte())
If ch = vbCr Then
' ignore
Continue While
End If
If ch = vbLf Then
Return sb.ToString()
End If
sb.Append(ch)
End While
 
' pause
Thread.Sleep(100)
End If
Loop
End Function
 
Private Sub Broadcast(text As String)
Console.WriteLine(text)
For Each client In connections
If client.Key <> Thread.CurrentThread.ManagedThreadId Then
Dim state = client.Value
state.Send(text)
End If
Next
End Sub
 
End Module</syntaxhighlight>
 
=={{header|C}}==
Line 141 ⟶ 278:
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 <sys/socket.h>
Line 389 ⟶ 526:
return 0;
}</syntaxhighlight>
 
=={{header|C sharp|C#}}==
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Net.Sockets;
Line 535 ⟶ 671:
}
}</syntaxhighlight>
 
=={{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.
 
<syntaxhighlight lang="coffeescript">
net = require("net")
sys = require("sys")
Line 648 ⟶ 783:
server = new ChatServer()
</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}}==
{{libheader|usocket}}
Line 835 ⟶ 806:
*USER-MANAGER*, or upon an error occurring.
 
<syntaxhighlight lang="common-lisp">
(ql:quickload '(:usocket :simple-actors :bordeaux-threads))
 
Line 1,012 ⟶ 983:
(make-thread #'accept-connections)
</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}}==
<syntaxhighlight lang="erlang">
-module(chat).
 
Line 1,079 ⟶ 1,211:
end.
</syntaxhighlight>
 
=={{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.
Line 1,087 ⟶ 1,218:
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 (
Line 1,269 ⟶ 1,400:
c.server.rem <- c.name
}</syntaxhighlight>
 
=={{header|Groovy}}==
{{trans|Java}}
<syntaxhighlight lang="groovy">class ChatServer implements Runnable {
private int port = 0
private List<Client> clientList = new ArrayList<>()
Line 1,428 ⟶ 1,558:
}
}</syntaxhighlight>
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">{-# LANGUAGE OverloadedStrings #-}
import Network
import System.IO
Line 1,519 ⟶ 1,648:
 
This is Unicon-specific:
<syntaxhighlight lang="unicon">global mlck, nCons, cons
 
procedure main()
Line 1,546 ⟶ 1,675:
}
end</syntaxhighlight>
 
=={{header|Java}}==
 
Line 1,553 ⟶ 1,681:
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.util.*;
Line 1,706 ⟶ 1,834:
}
</syntaxhighlight>
 
=={{header|JavaScript}}==
{{works with|Node.js}}
<syntaxhighlight lang="javascript">const net = require("net");
const EventEmitter = require("events").EventEmitter;
Line 1,857 ⟶ 1,984:
// Start the server!
server = new ChatServer();</syntaxhighlight>
 
=={{header|Julia}}==
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.
<syntaxhighlight lang="julia">
using HttpServer
using WebSockets
Line 1,945 ⟶ 2,071:
run(server,8000)
</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|Java}}
<syntaxhighlight lang="scala">import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
Line 2,101 ⟶ 2,226:
}
}</syntaxhighlight>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import asyncnet, asyncdispatch
 
type
Line 2,145 ⟶ 2,269:
asyncCheck serve()
runForever()</syntaxhighlight>
 
=={{header|Objeck}}==
<syntaxhighlight lang="objeck">
use System.IO.Net;
use System.Concurrency;
Line 2,258 ⟶ 2,381:
}
</syntaxhighlight>
 
=={{header|Ol}}==
<syntaxhighlight lang="scheme">
(define (timestamp) (syscall 201 "%c"))
 
Line 2,384 ⟶ 2,506:
(127.0.0.1 . 55320): see you..
</pre>
 
=={{header|Perl}}==
{{trans|Python}}
<syntaxhighlight lang="perl">use 5.010;
use strict;
use warnings;
Line 2,496 ⟶ 2,617:
}</syntaxhighlight>
===Alternate with both read and write queuing===
<syntaxhighlight lang="perl">#!/usr/bin/perl
 
use strict; # http://www.rosettacode.org/wiki/Chat_server
Line 2,576 ⟶ 2,697:
}
}</syntaxhighlight>
 
=={{header|Phix}}==
===server===
<!--<syntaxhighlight lang=Phix"phix">(notonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\ChatServer.exw
Line 2,751 ⟶ 2,871:
<!--</syntaxhighlight>-->
===client===
<!--<syntaxhighlight lang=Phix"phix">(notonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\ChatClient.exw
Line 2,994 ⟶ 3,114:
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
<syntaxhighlight lang=PicoLisp"picolisp">#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
 
(de chat Lst
Line 3,055 ⟶ 3,174:
| Connection closed.
| $</pre>
 
=={{header|Prolog}}==
Works with Swi-Prolog as of Jan 2019.
 
This version will load the server automatically on port 5000, adapt to your needs.
<syntaxhighlight lang="prolog">:- initialization chat_server(5000).
 
chat_server(Port) :-
Line 3,141 ⟶ 3,259:
msg_new_line('\n\r').
msg_by_user('~w> ~w').</syntaxhighlight>
 
=={{header|Python}}==
<syntaxhighlight lang="python">#!/usr/bin/env python
 
import socket
Line 3,221 ⟶ 3,338:
except (SystemExit, KeyboardInterrupt):
break</syntaxhighlight>
 
=={{header|R}}==
This implementation relies on the new server socket connection type introduced in R 4.0.0.
<syntaxhighlight lang=R"r">
chat_loop <- function(server, sockets, delay = 0.5) {
repeat {
Line 3,371 ⟶ 3,487:
 
start_chat_server()</syntaxhighlight>
 
=={{header|Racket}}==
 
This is a very basic chat server, but it does everything that is needed for this task.
 
<syntaxhighlight lang="racket">
#lang racket
 
Line 3,399 ⟶ 3,514:
((client (current-input-port) (current-output-port)))
</syntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
Line 3,405 ⟶ 3,519:
<div style="display:inline-block">{{trans|Python}}</div> (or at least started out that way)
{{works with|Rakudo|2016.07}}
<syntaxhighlight lang="raku" line>react {
my %connections;
Line 3,453 ⟶ 3,567:
* 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.
 
=={{header|Ruby}}==
<syntaxhighlight lang=Ruby"ruby">require 'gserver'
 
class ChatServer < GServer
Line 3,524 ⟶ 3,637:
ChatServer.new(7000, '0.0.0.0', 100, $stderr, true).start.join
</syntaxhighlight>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">
use std::collections::HashMap;
use std::io;
Line 3,624 ⟶ 3,736:
}
</syntaxhighlight>
 
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
<syntaxhighlight lang="tcl">package require Tcl 8.6
 
# Write a message to everyone except the sender of the message
Line 3,688 ⟶ 3,799:
set ::cmap {}; # Dictionary mapping nicks to channels
vwait forever; # Run event loop</syntaxhighlight>
 
=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang=vbnet>Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
 
Module Module1
 
Class State
Private ReadOnly client As TcpClient
Private ReadOnly sb As New StringBuilder
 
Public Sub New(name As String, client As TcpClient)
Me.Name = name
Me.client = client
End Sub
 
Public ReadOnly Property Name As String
 
Public Sub Send(text As String)
Dim bytes = Encoding.ASCII.GetBytes(String.Format("{0}" & vbCrLf, text))
client.GetStream().Write(bytes, 0, bytes.Length)
End Sub
End Class
 
ReadOnly connections As New Dictionary(Of Integer, State)
Dim listen As TcpListener
Dim serverThread As Thread
 
Sub Main()
listen = New TcpListener(Net.IPAddress.Parse("127.0.0.1"), 4004)
serverThread = New Thread(New ThreadStart(AddressOf DoListen))
serverThread.Start()
End Sub
 
Private Sub DoListen()
listen.Start()
Console.WriteLine("Server: Started server")
 
Do
Console.Write("Server: Waiting...")
Dim client = listen.AcceptTcpClient()
Console.WriteLine(" Connected")
 
' New thread with client
Dim clientThread As New Thread(New ParameterizedThreadStart(AddressOf DoClient))
 
clientThread.Start(client)
Loop
End Sub
 
Private Sub DoClient(client As TcpClient)
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId)
Dim bytes = Encoding.ASCII.GetBytes("Enter name: ")
client.GetStream().Write(bytes, 0, bytes.Length)
 
Dim done As Boolean
Dim name As String
Do
If Not client.Connected Then
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close()
Thread.CurrentThread.Abort() ' Kill thread
End If
 
name = Receive(client)
done = True
 
For Each cl In connections
Dim state = cl.Value
If state.Name = name Then
bytes = Encoding.ASCII.GetBytes("Name already registered. Please enter your name: ")
client.GetStream().Write(bytes, 0, bytes.Length)
done = False
End If
Next
Loop While Not done
 
connections.Add(Thread.CurrentThread.ManagedThreadId, New State(name, client))
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Broadcast(String.Format("+++ {0} arrived +++", name))
 
Do
Dim text = Receive(client)
If text = "/quit" Then
Broadcast(String.Format("Connection from {0} closed.", name))
connections.Remove(Thread.CurrentThread.ManagedThreadId)
Console.WriteLine(vbTab & "Total connections: {0}", connections.Count)
Exit Do
End If
 
If Not client.Connected Then
Exit Do
End If
 
Broadcast(String.Format("{0}> {1}", name, text))
Loop
 
Console.WriteLine("Client (Thread: {0}): Terminated!", Thread.CurrentThread.ManagedThreadId)
client.Close()
Thread.CurrentThread.Abort()
End Sub
 
Private Function Receive(client As TcpClient) As String
Dim sb As New StringBuilder
Do
If client.Available > 0 Then
While client.Available > 0
Dim ch = Chr(client.GetStream.ReadByte())
If ch = vbCr Then
' ignore
Continue While
End If
If ch = vbLf Then
Return sb.ToString()
End If
sb.Append(ch)
End While
 
' pause
Thread.Sleep(100)
End If
Loop
End Function
 
Private Sub Broadcast(text As String)
Console.WriteLine(text)
For Each client In connections
If client.Key <> Thread.CurrentThread.ManagedThreadId Then
Dim state = client.Value
state.Send(text)
End If
Next
End Sub
 
End Module</syntaxhighlight>
 
=={{header|Wren}}==
Line 3,832 ⟶ 3,806:
 
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"wren">/* chat_serverChat_server.wren */
 
class Clients {
Line 4,033 ⟶ 4,007:
<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.
<syntaxhighlight lang="c">/* gcc chat_serverChat_server.c -o chat_serverChat_server -lpthread -lwren -lm */
 
#include <sys/socket.h>
Line 4,313 ⟶ 4,287:
config.bindForeignMethodFn = &bindForeignMethod;
const char* module = "main";
const char* fileName = "chat_serverChat_server.wren";
script = readFile(fileName);
 
Line 4,390 ⟶ 4,364:
{{trans|Python}}
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, ...)
Line 4,481 ⟶ 4,455:
Connection closed by foreign host.
</pre>
 
{{omit from|AutoHotkey}}
{{omit from|Lilypond}}
{{omit from|ML/I}}
{{omit from|Mathematica}}
{{omit from|Maxima}}
{{omit from|ML/I}}
{{omit from|PARI/GP|No good way to access network}}
{{omit from|Retro}}
9,476

edits