Skip to content

Instantly share code, notes, and snippets.

@cirocorvino
Last active August 24, 2020 09:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cirocorvino/eebe5a16c2004524d5b7c09f936d52f9 to your computer and use it in GitHub Desktop.
Save cirocorvino/eebe5a16c2004524d5b7c09f936d52f9 to your computer and use it in GitHub Desktop.
C# simple chat server example
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ChatServerExample
{
/// <summary>
/// Console app that allows telnet client to connect and chat on the port 10000.
/// <para>Minimum sdk requirements: C# 5 and .Net 4.5 </para>
/// </summary>
class Program
{
static void Main(string[] args)
{
StartServer();
}
static void StartServer() {
List<Socket> clientSockets = new List<Socket>();
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, 10000));
server.Listen(backlog: 15);
Console.WriteLine($"Chat server is listening on port: {((IPEndPoint)server.LocalEndPoint).Port}");
var cts = new CancellationTokenSource();
Task.Run(() => {
while (true)
{
Console.WriteLine("Waiting for accept new client...");
var client = server.Accept();
if (!client.Connected)
{
Console.WriteLine("Client not connected");
continue;
}
Console.WriteLine($"Client connected from {client.ClientOrigin()}");
clientSockets.Add(client);
ClientCommunicationHandler(client);
}
}, cts.Token);
//dispatch every message to all connected clients
//Task.Run(async () =>
Task.Run(() =>
{
while (true)
{
var newMessages = Chat.NewMessages;
if (newMessages == null || newMessages.Count == 0)
continue;
BroadcastMessages(clientSockets, newMessages);
}
}, cts.Token);
Console.WriteLine("Press Return to exit");
Console.ReadLine();
cts.Cancel();
}
static async Task ClientCommunicationHandler(Socket clientSocket) {
try
{
using (var stream = new NetworkStream(clientSocket, true)) {
using (var reader = new StreamReader(stream, Encoding.ASCII, false, 10000, true)) {
using (var writer = new StreamWriter(stream, Encoding.ASCII, 10000, true))
{
writer.AutoFlush = true;
await writer.WriteLineAsync($"connected to chat server");
while (true) {
var msgFromClient = await reader.ReadLineAsync();
Console.WriteLine($"client from {clientSocket.ClientOrigin()} --> {msgFromClient}");
if(string.Compare(msgFromClient, "quit", ignoreCase: true) == 0)
{
break;
}
await Chat.AddNewMessage($"client from {clientSocket.ClientOrigin()} --> {msgFromClient}");
}
Console.WriteLine($"client from {clientSocket.ClientOrigin()} disconnected");
}
}
}
}
catch (Exception ex){
Console.WriteLine(ex.Message);
}
}
static void BroadcastMessages(List<Socket> clientSockets, List<Guid> newMessages)
{
foreach (var client in clientSockets)
{
using (var stream = new NetworkStream(client, false))
{
using (var writer = new StreamWriter(stream, Encoding.ASCII, 10000, true))
{
writer.AutoFlush = true;
foreach (var msgId in newMessages)
{
var msg = Chat.GetMessageByGuid(msgId);
if (msg.Contains(client.ClientOrigin())) {
continue;
}
writer.WriteLine(msg);
Chat.SetMessageAsBroadcasted(msgId);
}
}
}
}
}
}
public static class Chat {
private class Message {
public Guid id;
public string message;
public bool isNewMsg;
}
private static List<Message> chatMessage;
private static object m_lockChatMessage = new object();
public static List<Guid> NewMessages {
get {
lock (m_lockChatMessage)
{
if (chatMessage == null)
{
return null;
}
return chatMessage.Where(m => m != null && m.isNewMsg).Select(m => m.id).ToList();
}
}
}
public static string GetMessageByGuid(Guid id) {
lock (m_lockChatMessage)
{
return chatMessage.FirstOrDefault(m => m.id == id)?.message;
}
}
public static async Task AddNewMessage(string p_message)
{
lock (m_lockChatMessage)
{
if(chatMessage == null)
{
chatMessage = new List<Message>();
}
chatMessage.Add(new Message
{
id = Guid.NewGuid(),
message = p_message,
isNewMsg = true
});
}
}
public static void SetMessageAsBroadcasted(Guid id)
{
lock (m_lockChatMessage)
{
var msg = chatMessage.FirstOrDefault(m => m.id == id);
if (msg != null)
{
msg.isNewMsg = false;
}
}
}
}
public static class ExtMethods
{
public static string ClientOrigin(this Socket client)
{
return $"address: {((IPEndPoint)client.RemoteEndPoint).Address} - port: {((IPEndPoint)client.RemoteEndPoint).Port}";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment