/TCPChatServer

C# TCP chat server

Primary LanguageC#MIT LicenseMIT

C# message exchange server, with handshakes for authentication and a room system. Usage(unity):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
using Newtonsoft.Json;
using System.IO;
using System.Threading.Tasks;
using System.IO.Compression;
using UnityEngine.SceneManagement;

public struct HandshakeStruct
{
    public long clientUID; // no use at time
    public float gameVersion; // used for my game version, you can delete it here and on server
    public string passwordHash; // hash from password, not very secure lol)
    public string roomName; //name says it
    public HandshakeStruct(long uid,float ver,string hash, string roomName)
    {
        this.clientUID = uid;
        this.gameVersion = ver;
        this.passwordHash = hash;  
        this.roomName = roomName;
    }
};

public class ChatController : MonoBehaviour
{
    public TMPro.TMP_InputField chatInput;
    public TMPro.TMP_InputField chat;
    public static ChatController instance;
    public GameObject chatCanvas;
    public bool inRoom = false;

    TcpClient theClient;
    bool hndsSuccesful = false;

    const float maxTimer = 4f;
    float timer = maxTimer;

    private string localChat = "";

    private void Awake() // Some singleton stuff, don't look much at it
    {
        if(instance == null)
        {
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    public static string GetMD5FromString(string toGet) // Used for auth
    {
        using (var md5 = MD5.Create())
        {
            var hashB = md5.ComputeHash(Encoding.UTF8.GetBytes(toGet));
            return BitConverter.ToString(hashB);
        }
    }

    public void Connect(HandshakeStruct structH) // write your struct
    {
        if(theClient == null)
        {
            theClient = new TcpClient("yourdomain or ip", 1420);
            string conStr = "HANDSHAKE>"; //Separator that indicates a handshake

            HandshakeStruct hs = structH;
            conStr += JsonConvert.SerializeObject(hs); // Serializing a handshake using Newtonsoft.Json
            byte[] hndsB = Encoding.UTF8.GetBytes(conStr); // converting all to bytes
            List<byte> vs = new List<byte>(0);
            for (int i = 0; i < 1024; i++) // for fixed size of 1KB
            {
                vs.Add(255);
            }

            for (int i = 0; i < hndsB.Length; i++)
            {
                vs[i] = hndsB[i];
            }

            theClient.GetStream().Write(vs.ToArray(), 0, vs.Count);
            inRoom = true;
            chatInput.gameObject.SetActive(true);
            Debug.Log("Connected");
        }
    }

    // Update is called once per frame
    async void Update()
    {
        if (theClient != null)
        {
            try
            {
                byte[] buf = new byte[1024];
                await theClient.GetStream().ReadAsync(buf, 0, buf.Length); // Fetching new messages from other clients

                if (buf.Length > 0)
                {
                    List<byte> respBytes = new List<byte>();
                    foreach (var b in buf)
                    {
                        if (b != 255)
                        {
                            respBytes.Add(b);
                        }
                    }

                    string respString = Encoding.UTF8.GetString(respBytes.ToArray());
                    if (respString.Contains("HANDSHAKE SUCCESSFUL") && !hndsSuccesful)
                    {
                        hndsSuccesful = true;
                    }
                    if (string.IsNullOrEmpty(respString) || string.IsNullOrWhiteSpace(respString))
                    {
                        return;
                    }
                    localChat += respString + "\r\n";
                    timer = maxTimer;
                    chatCanvas.SetActive(true);
                    chat.text = localChat;
                }
            }
            catch
            {
                if(theClient != null)
                {
                    theClient.Close();
                    theClient = null;
                }
            }
        }
    }
    private void LateUpdate()
    {
        if(inRoom)
        {
            if (Input.GetKeyDown(KeyCode.T) && !chatInput.isFocused)
            {
                timer = maxTimer;
                if (SceneManager.GetActiveScene().name != "MainMeni")
                {
                    if (!chatInput.gameObject.activeInHierarchy)
                    {
                        chatCanvas.SetActive(!chatInput.gameObject.activeInHierarchy);
                        chatInput.gameObject.SetActive(!chatInput.gameObject.activeInHierarchy);
                        Cursor.lockState = CursorLockMode.None;
                        Cursor.visible = true;
                    }
                    else
                    {
                        chatCanvas.SetActive(!chatInput.gameObject.activeInHierarchy);
                        chatInput.gameObject.SetActive(!chatInput.gameObject.activeInHierarchy);
                        Cursor.lockState = CursorLockMode.Locked;
                        Cursor.visible = false;
                    }
                }
                else
                {
                    chatCanvas.SetActive(!chatInput.gameObject.activeInHierarchy);
                    chatInput.gameObject.SetActive(!chatInput.gameObject.activeInHierarchy);
                }
            }
            if (Input.GetKeyDown(KeyCode.Return))
            {
                timer = maxTimer;
                if (chatCanvas.activeInHierarchy)
                {
                    WriteMessage(chatInput);
                    chatInput.text = "";
                }
            }
            if (timer > 0f)
            {
                timer -= Time.deltaTime;
            }
            else if (!chatInput.isFocused)
            {
                chatInput.gameObject.SetActive(false);
                chatCanvas.SetActive(false);
                timer = maxTimer;
            }
        }
        else
        {
            chatInput.gameObject.SetActive(false);
            chatCanvas.SetActive(false);
        }
    }

    public void WriteMessage(TMPro.TMP_InputField infield)
    {
        string message = "[" + Photon.Pun.PhotonNetwork.LocalPlayer.NickName + "]" + infield.text; //Formatting with nick ex. [Amogus]Sssss
        if(theClient != null)
        {
            if (string.IsNullOrEmpty(infield.text) || string.IsNullOrWhiteSpace(infield.text) || message.Contains("STPPOINT")) 
            {
                return;
            }
            byte[] msbody = Encoding.UTF8.GetBytes(message); //encode the message
            List<byte> vs = new List<byte>(1024);
            for (int i = 0; i < 1024; i++)
            {
                vs.Add(255); // used as null characters, theese guys(ÿ) will be igonred so dont write them! Idk why i choose them you can change it
            }

            for (int i = 0; i < msbody.Length; i++)
            {
                vs[i] = msbody[i];
            }

            theClient.GetStream().Write(vs.ToArray(), 0, vs.Count);

            byte[] msbody2 = Encoding.UTF8.GetBytes("STPPOINT"); // STP POINT is just like end character of message, it is written after every message
            List<byte> vs2 = new List<byte>(1024);
            for (int i = 0; i < 1024; i++)
            {
                vs2.Add(255);
            }

            for (int i = 0; i < msbody2.Length; i++)
            {
                vs2[i] = msbody2[i];
            }

            theClient.GetStream().Write(vs2.ToArray(), 0, vs2.Count);
        }
    }
    public async void Disconnect()
    {
        if (theClient != null)
        {
            chatCanvas.SetActive(false);
            localChat = "";
            inRoom = false;
            await Task.Delay(100);
            theClient.Close();
            theClient = null;
        }
    }
    private void OnApplicationQuit()
    {
        if(theClient != null)
        {
            theClient.Close();
            theClient = null;
        }
    }
}