본문 바로가기

C#/Network

C# TCPServer with WebSocket

C# TCPServer with WebSocket

 

 

public class TcpServerWS
    {

        private static TcpServerWS _instance;
        public static TcpServerWS Instance { get { return _instance; } }

        private TcpListener m_TcpListener;
        private int _nPort = 13000;
        private string _sIPAddress;

        private List<DeviceTcpClient> m_Clients;
        private Thread m_ListenThread;


        public TcpServerWS()
        {
            this.m_Clients = new List<DeviceTcpClient>();
        }
        

        public void ServerStart()
        {
            m_ListenThread = new Thread(StartServer);
            m_ListenThread.Start();
        }

        private void StartServer()
        {
            try
            {
                this.m_TcpListener = new TcpListener(IPAddress.Any, this._nPort);
                this.m_TcpListener.Start();
                Console.WriteLine("TV server has started.");

                while (true)
                {
                    TcpClient client = this.m_TcpListener.AcceptTcpClient();

                    Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
                    clientThread.Start(client);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                this.m_TcpListener.Stop();
                Console.WriteLine("TV server has ended.");
            }
        }

        private void HandleClient(object c)
        {
            TcpClient client = (TcpClient)c;
            NetworkStream clientStream = client.GetStream();

            byte[] message = new byte[client.ReceiveBufferSize];
            int byteRead;

            while (true)
            {
                byteRead = 0;

                try
                {
                    byteRead = clientStream.Read(message, 0, client.ReceiveBufferSize);
                }
                catch
                {
                    break;
                }

                if (byteRead == 0)
                {
                    break;
                }



                string receiveMessage = System.Text.ASCIIEncoding.GetEncoding("euc-kr").GetString(message, 0, byteRead);
                var sb = new StringBuilder("new byte[] { ");
                foreach (var b in message)
                {
                    sb.Append(b + ", ");
                }
                sb.Append("}");



                if (new System.Text.RegularExpressions.Regex("^GET").IsMatch(receiveMessage))
                {
                    const string eol = "\r\n"; // HTTP/1.1 defines the sequence CR LF as the end-of-line marker

                    Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + eol
                        + "Connection: Upgrade" + eol
                        + "Upgrade: websocket" + eol
                        + "Sec-WebSocket-Accept: " + Convert.ToBase64String(
                            System.Security.Cryptography.SHA1.Create().ComputeHash(
                                Encoding.UTF8.GetBytes(
                                    new System.Text.RegularExpressions.Regex("Sec-WebSocket-Key: (.*)").Match(receiveMessage).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
                                )
                            )
                        ) + eol
                        + eol);

                    clientStream.Write(response, 0, response.Length);
                }
                else
                {
                    string decodeMessage = DecodeMessageFromWebSockClient(message, byteRead);
                    //string decodeMessage = GetMessage(message);
                    Console.WriteLine("DecodeMessage : " + decodeMessage);

                    var messages = decodeMessage.Split('|');
                    string deviceID = "";

                    if (messages != null)
                    {
                        if (messages.Length == 2)
                        {
                            if (messages[0].ToLower() == "id")
                            {
                                deviceID = messages[1];

                                DeviceTcpClient deviceClient = new DeviceTcpClient { Client = client, DeviceID = deviceID };
                                this.m_Clients.Add(deviceClient);
                                Console.WriteLine(String.Format("[{0}] is logged in. Connected device count is {1}.", deviceID, this.m_Clients.Count));

                                //SendMessageToWebSocketClient(client, "HelloClient!!!!!");
                            }
                        }
                    }
                    
                }

            }

            client.Close();

            DeviceTcpClient deleteItem = null;
            foreach (var item in m_Clients)
            {
                if (item.Client == client)
                {
                    deleteItem = item;
                    break;
                }
            }

            if (deleteItem != null)
            {
                Console.WriteLine(String.Format("[{0}] is logged out. Connected device count is {1}.", deleteItem.DeviceID, this.m_Clients.Count - 1));
                m_Clients.Remove(deleteItem);
            }
        }

        public TcpClient FindDevice(string id)
        {
            TcpClient result = null;

            foreach (var item in m_Clients)
            {
                if (item.DeviceID == id)
                {
                    result = item.Client;
                    break;
                }
            }

            return result;
        }

        private string DecodeMessageFromWebSockClient(Byte[] b, int len)
        {
            try
            {
                byte rLength = 0;
                int rMaskIndex = 2;
                int rDataStart = 0;
                //b[0] is always text in my case so no need to check;
                byte data = b[1];
                byte op = (byte)127;
                rLength = (byte)(data & op);

                if (rLength == (byte)126) rMaskIndex = 4;
                if (rLength == (byte)127) rMaskIndex = 10;

                byte[] masks = new byte[4];

                int j = 0;
                int i = 0;
                for (i = rMaskIndex; i < (rMaskIndex + 4); i++)
                {
                    masks[j] = b[i];
                    j++;
                }

                rDataStart = rMaskIndex + 4;

                int messLen = len - rDataStart;

                byte[] message = new byte[messLen];

                for (i = rDataStart, j = 0; i < len; i++, j++)
                {
                    message[j] = (byte)(b[i] ^ masks[j % 4]);
                }

                var parseMessage = Encoding.UTF8.GetString(message);
                return parseMessage;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return null;
        }

        public string DecodeMessage(Byte[] bytes)
        {
            string incomingData = string.Empty;
            byte secondByte = bytes[1];
            int dataLength = secondByte & 127;
            int indexFirstMask = 2;
            if (dataLength == 126)
                indexFirstMask = 4;
            else if (dataLength == 127)
                indexFirstMask = 10;

            IEnumerable<byte> keys = bytes.Skip(indexFirstMask).Take(4);
            int indexFirstDataByte = indexFirstMask + 4;

            byte[] decoded = new byte[bytes.Length - indexFirstDataByte];
            for (int i = indexFirstDataByte, j = 0; i < bytes.Length; i++, j++)
            {
                decoded[j] = (byte)(bytes[i] ^ keys.ElementAt(j % 4));
            }

            return Encoding.UTF8.GetString(decoded, 0, decoded.Length);
        }


        public void SendMessageToClient(TcpClient c, string msg)
        {
            try
            {
                TcpClient client = (TcpClient)c;
                NetworkStream clientStream = client.GetStream();
                Byte[] buffer = System.Text.ASCIIEncoding.UTF8.GetBytes(msg);
                clientStream.Write(buffer, 0, buffer.Length);
                clientStream.Flush();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public void SendMessageToWebSocketClient(TcpClient c, string msg)
        {
            TcpClient client = (TcpClient)c;
            NetworkStream clientStream = client.GetStream();
            byte[] rawData = System.Text.ASCIIEncoding.UTF8.GetBytes(msg);

            int frameCount = 0;
            byte[] frame = new byte[10];

            frame[0] = (byte)129;

            if (rawData.Length <= 125)
            {
                frame[1] = (byte)rawData.Length;
                frameCount = 2;
            }
            else if (rawData.Length >= 126 && rawData.Length <= 65535)
            {
                frame[1] = (byte)126;
                int len = rawData.Length;
                frame[2] = (byte)((len >> 8) & (byte)255);
                frame[3] = (byte)(len & (byte)255);
                frameCount = 4;
            }
            else
            {
                frame[1] = (byte)127;
                int len = rawData.Length;
                frame[2] = (byte)((len >> 56) & (byte)255);
                frame[3] = (byte)((len >> 48) & (byte)255);
                frame[4] = (byte)((len >> 40) & (byte)255);
                frame[5] = (byte)((len >> 32) & (byte)255);
                frame[6] = (byte)((len >> 24) & (byte)255);
                frame[7] = (byte)((len >> 16) & (byte)255);
                frame[8] = (byte)((len >> 8) & (byte)255);
                frame[9] = (byte)(len & (byte)255);
                frameCount = 10;
            }

            int bLength = frameCount + rawData.Length;

            byte[] reply = new byte[bLength];

            int bLim = 0;
            for (int i = 0; i < frameCount; i++)
            {
                reply[bLim] = frame[i];
                bLim++;
            }
            for (int i = 0; i < rawData.Length; i++)
            {
                reply[bLim] = rawData[i];
                bLim++;
            }

            clientStream.Write(reply, 0, reply.Length);
            clientStream.Flush();
        }

        public void ServerClose()
        {
            if (m_Clients != null)
            {
                for (int i = 0; i < m_Clients.Count; i++)
                {
                    TcpClient client = m_Clients[i].Client;
                    client.Close();
                }

                m_Clients.Clear();
            }

            if (m_TcpListener != null)
            {
                m_TcpListener.Stop();
            }

            if (m_ListenThread != null)
            {
                m_ListenThread.Abort();
            }
        }
    }

'C# > Network' 카테고리의 다른 글

C# TCP Client  (0) 2020.08.14
C# Multi Thread TcpServer  (0) 2020.08.14
C# UDP  (0) 2020.08.13
C# WOL 컴퓨터 원격 온오프  (0) 2020.08.07
C# Ping 테스트, 해당 IP 장치 이름 가져오기  (0) 2020.08.07