September Morn Update
This commit is contained in:
parent
4e2d22a71d
commit
aac6731f2c
6856 changed files with 141342 additions and 21127 deletions
156
Task/Chat-server/Groovy/chat-server.groovy
Normal file
156
Task/Chat-server/Groovy/chat-server.groovy
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
class ChatServer implements Runnable {
|
||||
private int port = 0
|
||||
private List<Client> clientList = new ArrayList<>()
|
||||
|
||||
ChatServer(int port) {
|
||||
this.port = port
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyInfiniteLoopStatement")
|
||||
@Override
|
||||
void run() {
|
||||
try {
|
||||
ServerSocket serverSocket = new ServerSocket(port)
|
||||
while (true) {
|
||||
Socket socket = serverSocket.accept()
|
||||
new Thread(new Client(socket)).start()
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean registerClient(Client client) {
|
||||
for (Client other : clientList) {
|
||||
if (other.clientName.equalsIgnoreCase(client.clientName)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
clientList.add(client)
|
||||
return true
|
||||
}
|
||||
|
||||
private void deRegisterClient(Client client) {
|
||||
boolean wasRegistered
|
||||
synchronized (this) {
|
||||
wasRegistered = clientList.remove(client)
|
||||
}
|
||||
if (wasRegistered) {
|
||||
broadcast(client, "--- " + client.clientName + " left ---")
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized String getOnlineListCSV() {
|
||||
StringBuilder sb = new StringBuilder()
|
||||
sb.append(clientList.size()).append(" user(s) online: ")
|
||||
def it = clientList.iterator()
|
||||
if (it.hasNext()) {
|
||||
sb.append(it.next().clientName)
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
sb.append(", ")
|
||||
sb.append(it.next().clientName)
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private void broadcast(Client fromClient, String msg) {
|
||||
// Copy client list (don't want to hold lock while doing IO)
|
||||
List<Client> clients
|
||||
synchronized (this) {
|
||||
clients = new ArrayList<>(this.clientList)
|
||||
}
|
||||
for (Client client : clients) {
|
||||
if (client == fromClient) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
client.write(msg + "\r\n")
|
||||
} catch (Exception ignored) {
|
||||
// empty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Client implements Runnable {
|
||||
private Socket socket = null
|
||||
private Writer output = null
|
||||
private String clientName = null
|
||||
|
||||
Client(Socket socket) {
|
||||
this.socket = socket
|
||||
}
|
||||
|
||||
@Override
|
||||
void run() {
|
||||
try {
|
||||
socket.setSendBufferSize(16384)
|
||||
socket.setTcpNoDelay(true)
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))
|
||||
output = new OutputStreamWriter(socket.getOutputStream())
|
||||
write("Please enter your name: ")
|
||||
String line
|
||||
while (null != (line = input.readLine())) {
|
||||
if (null == clientName) {
|
||||
line = line.trim()
|
||||
if (line.isEmpty()) {
|
||||
write("A name is required. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
clientName = line
|
||||
if (!registerClient(this)) {
|
||||
clientName = null
|
||||
write("Name already registered. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
write(getOnlineListCSV() + "\r\n")
|
||||
broadcast(this, "+++ " + clientName + " arrived +++")
|
||||
continue
|
||||
}
|
||||
if (line.equalsIgnoreCase("/quit")) {
|
||||
return
|
||||
}
|
||||
broadcast(this, clientName + "> " + line)
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
// empty
|
||||
} finally {
|
||||
deRegisterClient(this)
|
||||
output = null
|
||||
try {
|
||||
socket.close()
|
||||
} catch (Exception ignored) {
|
||||
// empty
|
||||
}
|
||||
socket = null
|
||||
}
|
||||
}
|
||||
|
||||
void write(String msg) {
|
||||
output.write(msg)
|
||||
output.flush()
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean equals(client) {
|
||||
return (null != client) && (client instanceof Client) && (null != clientName) && clientName == client.clientName
|
||||
}
|
||||
|
||||
@Override
|
||||
int hashCode() {
|
||||
int result
|
||||
result = (socket != null ? socket.hashCode() : 0)
|
||||
result = 31 * result + (output != null ? output.hashCode() : 0)
|
||||
result = 31 * result + (clientName != null ? clientName.hashCode() : 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
static void main(String[] args) {
|
||||
int port = 4004
|
||||
if (args.length > 0) {
|
||||
port = Integer.parseInt(args[0])
|
||||
}
|
||||
new ChatServer(port).run()
|
||||
}
|
||||
}
|
||||
153
Task/Chat-server/Kotlin/chat-server.kotlin
Normal file
153
Task/Chat-server/Kotlin/chat-server.kotlin
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.io.OutputStreamWriter
|
||||
import java.io.Writer
|
||||
import java.net.ServerSocket
|
||||
import java.net.Socket
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
|
||||
class ChatServer private constructor(private val port: Int) : Runnable {
|
||||
private val clients = ArrayList<Client>()
|
||||
|
||||
private val onlineListCSV: String
|
||||
@Synchronized get() {
|
||||
val sb = StringBuilder()
|
||||
sb.append(clients.size).append(" user(s) online: ")
|
||||
for (i in clients.indices) {
|
||||
sb.append(if (i > 0) ", " else "").append(clients[i].clientName)
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
try {
|
||||
val ss = ServerSocket(port)
|
||||
while (true) {
|
||||
val s = ss.accept()
|
||||
Thread(Client(s)).start()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun registerClient(client: Client): Boolean {
|
||||
for (otherClient in clients) {
|
||||
if (otherClient.clientName!!.equals(client.clientName!!, ignoreCase = true)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
clients.add(client)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun deRegisterClient(client: Client) {
|
||||
var wasRegistered = false
|
||||
synchronized(this) {
|
||||
wasRegistered = clients.remove(client)
|
||||
}
|
||||
if (wasRegistered) {
|
||||
broadcast(client, "--- " + client.clientName + " left ---")
|
||||
}
|
||||
}
|
||||
|
||||
private fun broadcast(fromClient: Client, msg: String) {
|
||||
// Copy client list (don't want to hold lock while doing IO)
|
||||
var clients: List<Client> = Collections.emptyList()
|
||||
synchronized(this) {
|
||||
clients = ArrayList(this.clients)
|
||||
}
|
||||
for (client in clients) {
|
||||
if (client.equals(fromClient)) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
client.write(msg + "\r\n")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inner class Client internal constructor(private var socket: Socket?) : Runnable {
|
||||
private var output: Writer? = null
|
||||
var clientName: String? = null
|
||||
|
||||
override fun run() {
|
||||
try {
|
||||
socket!!.sendBufferSize = 16384
|
||||
socket!!.tcpNoDelay = true
|
||||
val input = BufferedReader(InputStreamReader(socket!!.getInputStream()))
|
||||
output = OutputStreamWriter(socket!!.getOutputStream())
|
||||
write("Please enter your name: ")
|
||||
var line: String
|
||||
while (true) {
|
||||
line = input.readLine()
|
||||
if (null == line) {
|
||||
break
|
||||
}
|
||||
if (clientName == null) {
|
||||
line = line.trim { it <= ' ' }
|
||||
if (line.isEmpty()) {
|
||||
write("A name is required. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
clientName = line
|
||||
if (!registerClient(this)) {
|
||||
clientName = null
|
||||
write("Name already registered. Please enter your name: ")
|
||||
continue
|
||||
}
|
||||
write(onlineListCSV + "\r\n")
|
||||
broadcast(this, "+++ $clientName arrived +++")
|
||||
continue
|
||||
}
|
||||
if (line.equals("/quit", ignoreCase = true)) {
|
||||
return
|
||||
}
|
||||
broadcast(this, "$clientName> $line")
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
deRegisterClient(this)
|
||||
output = null
|
||||
try {
|
||||
socket!!.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
socket = null
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
internal fun write(msg: String) {
|
||||
output!!.write(msg)
|
||||
output!!.flush()
|
||||
}
|
||||
|
||||
internal fun equals(client: Client?): Boolean {
|
||||
return (client != null
|
||||
&& clientName != null
|
||||
&& client.clientName != null
|
||||
&& clientName == client.clientName)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
var port = 4004
|
||||
if (args.isNotEmpty()) {
|
||||
port = Integer.parseInt(args[0])
|
||||
}
|
||||
ChatServer(port).run()
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Task/Chat-server/Prolog/chat-server.pro
Normal file
81
Task/Chat-server/Prolog/chat-server.pro
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
:- initialization chat_server(5000).
|
||||
|
||||
chat_server(Port) :-
|
||||
tcp_socket(Socket),
|
||||
tcp_bind(Socket, Port),
|
||||
tcp_listen(Socket, 5),
|
||||
tcp_open_socket(Socket, AcceptFd, _),
|
||||
dispatch(AcceptFd).
|
||||
|
||||
dispatch(AcceptFd) :-
|
||||
tcp_accept(AcceptFd, Socket, _),
|
||||
thread_create(process_client(Socket, _), _, [detached(true)]),
|
||||
dispatch(AcceptFd).
|
||||
|
||||
process_client(Socket, _) :-
|
||||
setup_call_cleanup(
|
||||
tcp_open_socket(Socket, Str),
|
||||
handle_connection(Str),
|
||||
close(Str)).
|
||||
|
||||
% a connection was made, get the username and add the streams so the
|
||||
% client can be broadcast to.
|
||||
handle_connection(Str) :-
|
||||
send_msg(Str, msg_welcome, []),
|
||||
repeat,
|
||||
send_msg(Str, msg_username, []),
|
||||
read_line_to_string(Str, Name),
|
||||
connect_user(Name, Str), !.
|
||||
|
||||
% connections are stored here
|
||||
:- dynamic(connected/2).
|
||||
|
||||
connect_user(Name, Str) :-
|
||||
connected(Name, _),
|
||||
send_msg(Str, msg_username_taken, []),
|
||||
fail.
|
||||
connect_user(Name, Str) :-
|
||||
\+ connected(Name, _),
|
||||
send_msg(Str, msg_welcome_name, Name),
|
||||
|
||||
% make sure that the connection is removed when the client leaves.
|
||||
setup_call_cleanup(
|
||||
assert(connected(Name, Str)),
|
||||
(
|
||||
broadcast(Name, msg_joined, Name),
|
||||
chat_loop(Name, Str), !,
|
||||
broadcast(Name, msg_left, Name)
|
||||
),
|
||||
retractall(connected(Name, _))
|
||||
).
|
||||
|
||||
% wait for a line to be sent then broadcast to the rest of the clients
|
||||
% finish this goal when the client disconnects (end of stream)
|
||||
chat_loop(Name, Str) :-
|
||||
read_line_to_string(Str, S),
|
||||
dif(S, end_of_file),
|
||||
broadcast(Name, msg_by_user, [Name, S]),
|
||||
chat_loop(Name, Str).
|
||||
chat_loop(_, Str) :- at_end_of_stream(Str).
|
||||
|
||||
% send a message to all connected clients except Name (the sender)
|
||||
broadcast(Name, Msg, Params) :-
|
||||
forall(
|
||||
(connected(N, Str), dif(N, Name)),
|
||||
(send_msg(Str, Msg, Params), send_msg(Str, msg_new_line, []))
|
||||
).
|
||||
|
||||
send_msg(St, MsgConst, Params) :-
|
||||
call(MsgConst, Msg),
|
||||
format(St, Msg, Params),
|
||||
flush_output(St).
|
||||
|
||||
% constants for the various message types that are sent
|
||||
msg_welcome('Welcome to Chatalot\n\r').
|
||||
msg_username('Please enter your nickname: ').
|
||||
msg_welcome_name('Welcome ~p\n\r').
|
||||
msg_joined(' -- "~w" has joined the chat --').
|
||||
msg_left(' -- "~w" has left the chat. --').
|
||||
msg_username_taken('That username is already taken, choose another\n\r').
|
||||
msg_new_line('\n\r').
|
||||
msg_by_user('~w> ~w').
|
||||
134
Task/Chat-server/Visual-Basic-.NET/chat-server.visual
Normal file
134
Task/Chat-server/Visual-Basic-.NET/chat-server.visual
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue