0

I need to implement HTTP protocol through TCP. I already had a TCP/IP client-server program which had been working absolutely fine.

Now, I have done some minor change in the source code so that it behaves as an HTTP client-server. But, unfortunately it stopped working.

The following code ...

    public void Write(string str)
    {
        if (IsConnected)
        {
            byte[] strBytes = Encoding.UTF8.GetBytes(str);
            byte[] lenBytes = BitConverter.GetBytes(strBytes.Length);
            Array.Reverse(lenBytes);
            writer.Write(lenBytes);
            writer.Write(strBytes);
            writer.Flush();
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public string Read()
    {
        if (IsConnected)
        {
            byte[] lenBytes = reader.ReadBytes(4);
            Array.Reverse(lenBytes);
            int len = BitConverter.ToInt32(lenBytes, 0);
            byte[] bytes = reader.ReadBytes(len);
            string str = Encoding.UTF8.GetString(bytes);

            return str;
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

is changed to:

    public void Write(string str)
    {
        if (IsConnected)
        {
            byte[] send = Encoding.ASCII.GetBytes(str);
            writer.Write(send);
            writer.Flush();
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public string Read()
    {
        if (IsConnected)
        {
            StreamReader sr = new StreamReader(stream);
            string str = sr.ReadToEnd();

            return str;
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

What is the issue here?


Detailed Source Code

The following class is used by both server program and client program.

modified:

namespace MyClientServer
{
    public class ClientClass
    {
        private string Host { get; set; }
        private int Port { get; set; }

        private bool IsConnected = false;

        public string ID { get; private set; }
        public TcpClient Tcp { get; private set; }

        NetworkStream stream;
        private StreamReader sr;
        private StreamWriter writer;

        public ClientClass()
        {
            Random rnd = new Random();
            ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
        }

        //constructor for server program.
        public ClientClass(TcpListener listener)
        {
            Tcp = listener.AcceptTcpClient();

            Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
            Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;

            IsConnected = true;

            stream = Tcp.GetStream();
            sr = new StreamReader(stream);
            writer = new StreamWriter(stream);

            ID = Read();

            Console.WriteLine("Client [{0}] is now connected.", ID);

        }

        public bool Connect()
        {
            if (IsConnected == false)
            {
                Console.WriteLine("Client [{0}] is now connected.", ID);

                IsConnected = true;

                Tcp = new TcpClient(Host, Port);

                stream = Tcp.GetStream();
                sr = new StreamReader(stream);
                writer = new StreamWriter(stream);

                return true;
            }

            return false;
        }

        //constructor for client.
        public ClientClass(string host, int port)
        {
            Random rnd = new Random();
            ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
            Host = host;
            Port = port;
        }

        public void Write(string str)
        {
            if (IsConnected)
            {
                byte[] send = Encoding.ASCII.GetBytes(str);
                writer.Write(send);
                writer.Flush();
            }
            else
            {
                throw new Exception("Client " + ID + " is not connected!");
            }
        }

        public string Read()
        {
            if (IsConnected)
            {
                StreamReader sr = new StreamReader(stream);
                string str = sr.ReadToEnd();

                return str;
            }
            else
            {
                throw new Exception("Client " + ID + " is not connected!");
            }
        }

        public void PrintID()
        {
            Console.WriteLine("Client ID = {0}", ID);
        }

        public void SendIdToServer()
        {
            this.Write(ID);
        }

        public bool Disconnect()
        {
            if (IsConnected)
            {
                if (Tcp != null)
                {
                    Tcp.Close();
                    Tcp = null;

                    Console.WriteLine("\nClient [{0}] is now disconnected.", ID);

                    return true;
                }
            }

            return false;
        }        
    }
}

original:

namespace MyClientServer
{
    public class ClientClass
    {
        private string Host { get; set; }
        private int Port { get; set; }

        private bool IsConnected = false;

        public string ID { get; private set; }
        public TcpClient Tcp { get; private set; }

        private BinaryReader reader;
        private BinaryWriter writer;

        public ClientClass()
        {
            Random rnd = new Random();
            ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
        }

        //constructor for server program.
        public ClientClass(TcpListener listener)
        {
            Tcp  = listener.AcceptTcpClient();

            Host = ((IPEndPoint)Tcp.Client.RemoteEndPoint).Address.ToString();
            Port = ((IPEndPoint)Tcp.Client.LocalEndPoint).Port;

            IsConnected = true;

            NetworkStream stream = Tcp.GetStream();
            reader = new BinaryReader(stream);
            writer = new BinaryWriter(stream);

            ID = Read();

            Console.WriteLine("Client [{0}] is now connected.", ID);

        }

        public bool Connect()
        {
            if (IsConnected == false)
            {
                Console.WriteLine("Client [{0}] is now connected.", ID);

                IsConnected = true;

                Tcp = new TcpClient(Host, Port);

                NetworkStream stream = Tcp.GetStream();
                reader = new BinaryReader(stream);
                writer = new BinaryWriter(stream);

                return true;
            }

            return false;
        }

        //constructor for client.
        public ClientClass(string host, int port)
        {
            Random rnd = new Random();
            ID = AlphaNumRandom.GenerateUpperCaseString(5, rnd);
            Host = host;
            Port = port;
        }

        public void Write(string str)
        {
            if (IsConnected)
            {
                byte[] strBytes = Encoding.UTF8.GetBytes(str);
                byte[] lenBytes = BitConverter.GetBytes(strBytes.Length);
                Array.Reverse(lenBytes);
                writer.Write(lenBytes);
                writer.Write(strBytes);
                writer.Flush();
            }
            else
            {
                throw new Exception("Client " + ID + " is not connected!");
            }
        }

        public string Read()
        {
            if (IsConnected)
            {
                byte[] lenBytes = reader.ReadBytes(4);
                Array.Reverse(lenBytes);
                int len = BitConverter.ToInt32(lenBytes, 0);
                byte[] bytes = reader.ReadBytes(len);
                string str = Encoding.UTF8.GetString(bytes);

                return str;
            }
            else
            {
                throw new Exception("Client " + ID + " is not connected!");
            }
        }

        public void PrintID()
        {
            Console.WriteLine("Client ID = {0}", ID);
        }

        public void SendIdToServer()
        {
            this.Write(ID);
        }

        public bool Disconnect()
        {
            if (IsConnected)
            {
                if (Tcp != null)
                {
                    Tcp.Close();
                    Tcp = null;

                    Console.WriteLine("\nClient [{0}] is now disconnected.", ID);

                    return true;
                }
            }

            return false;
        }
    }
}
user366312
  • 16,949
  • 65
  • 235
  • 452
  • A stream in Windows does not end until it is closed. When it is used to read a file Windows will close the stream. When a stream is used to connect two processes a process need to close the stream. When the stream is used with TCP the stream is closed when the connection closed. – jdweng Feb 29 '20 at 16:26
  • Why `Encoding.ASCII.GetBytes(str)`? Can the ASCII encoder *understand* all strings content here? The reader also initializes the StreamReader as `StreamReader sr = new StreamReader(stream);`, which assumes UTF8 encoding (NO-BOM, so it doesn't check.). – Jimi Feb 29 '20 at 16:43
  • @Jimi, *Why `Encoding.ASCII.GetBytes(str)`?* --- coz, HTTP uses simple text,,,,, *The reader also initializes the `StreamReader as StreamReader sr = new StreamReader(stream);`, which assumes UTF8 encoding (NO-BOM, so it doesn't check.).* --- UTF8 is dropped altogether in the new code. – user366312 Feb 29 '20 at 16:50
  • Nope, you have `StreamReader sr = new StreamReader(stream);` in the *new code*. StreamReader here assumes the Stream is UTF-8 encoded. The two, reader and writer, can *talk* if all chars are limited to the ASCII table. If that's the case, then specify ASCII encoding in the StreamReader constuctor (I didn't read all the rest - this is a game-stopper in my book). I don't know what is *simple text*. You send bytes through a HTTP connection. – Jimi Feb 29 '20 at 16:54

1 Answers1

0

I took the advice of @Jimi and also took a look at the source code from this link.

Now my source code looks like the following:

    public string Read()
    {
        if (IsConnected)
        {
            byte[] buffer = new byte[Tcp.ReceiveBufferSize];//create a byte array
            int bytesRead = stream.Read(buffer, 0, Tcp.ReceiveBufferSize);//read count
            string str = Encoding.ASCII.GetString(buffer, 0, bytesRead);//convert to string
            return str;
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

    public void Write(string str)
    {
        if (IsConnected)
        {
            byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(str);
            stream.Write(bytesToSend, 0, bytesToSend.Length);
            stream.Flush();
        }
        else
        {
            throw new Exception("Client " + ID + " is not connected!");
        }
    }

and, it is working fine.

user366312
  • 16,949
  • 65
  • 235
  • 452