简体   繁体   中英

NetworkStream.Write data seems not to arrive at receiving socket

C# System.Net,Sockets

I'm having a problem where I cannot figure out what I might be doing wrong.

The story is, I send byte[] application data from TcpClient socket to another TcpClient socket. It all works great, until I add a custom pseudo Athentication test before the application data is sent, after which the send and receive which originally worked, fails.

I say fails, but what actually occurs is that it only appears to get 3 bytes all set to 0 at the read socket.

The Authenticate method does the following. The server end sends 1 byte of data (0-85), the client receives it, treats it as an int, multiplies it by 3 and sends a byte back to server. Server checks the value, and sends another byte back set to 1.

All of that seems to work fine, but together the data sent by cliend after authentication does not appear to be received, just 3 bytes set to 0.

I want the socket to remain open over the lifetime of the program, so I cannot dispose the stream, as that will also dispose the socket.

Here is the full code for both client and server, in the hope someone might see my mistake, or an issue I have missed.

The code is intentionally without error checking for brevity, and is very basic to just show the problem.

Note, that if both Authenticate methods simply return true, then the code works exactly how I'd expect it.

Server.

class Program
    {
        static Random rnd = new Random(Guid.NewGuid().GetHashCode());
        static void Main(string[] args)
        {
            Process p = Process.Start(@"C:\Users\Teddy\Documents\visual studio 2015\code\Readissue\TheClient\bin\Debug\TheClient.exe");

            Console.Title = "Server";

            TcpListener lis = new TcpListener(
                new IPEndPoint(
                    IPAddress.Any, 4000
                    ));

            lis.Start();

            TcpClient cli = lis.AcceptTcpClient();
            NetworkStream ns = cli.GetStream();

            if (Authenticate(cli, ns))
            {
                Console.WriteLine("Good!");
                // This condition is met
            }
            else
            {
                Console.WriteLine("Bad!");
                Console.ReadLine();
                return;
            }

            // Wait until Carrier class of client
            // Sends data
            while (!ns.DataAvailable)
            {
                Thread.Sleep(100);
            }
            Console.WriteLine("DataAvailable");

            byte[] buffer = new byte[2048];
            //bytesread is always the value of 3.
            int bytesread = ns.Read(buffer, 0, buffer.Length);
            string sdata = Encoding.ASCII.GetString(buffer).Substring(0, bytesread);
            Console.WriteLine(sdata);
            Console.ReadLine();

            p.Kill();
            p.Close();

        }

        private static bool Authenticate(TcpClient cli, NetworkStream ns)
        {
            //return true;
            byte[] rcv = new byte[1];
            int isnd = rnd.Next(0, 85);
            byte[] snd = new byte[1] { (byte)isnd };

            //Sends a random number
            //and waits for response
            ns.Write(snd, 0, snd.Length);
            while (!ns.DataAvailable)
            {
                Thread.Sleep(10);
            }

            // Expects response to be 
            // random number x 3
            int br = ns.Read(rcv, 0, rcv.Length);
            int ircv = rcv[0];

            int iok;
            if (ircv == (isnd * 3))
            {
                // Confirm random number x 3
                iok = 1;
                byte[] bok = new byte[1] { (byte)iok };
                ns.Write(bok, 0, snd.Length);
                return true;
            }
            else
            {
                iok = 0;
                byte[] bok = new byte[1] { (byte)iok };
                ns.Write(bok, 0, snd.Length);
                return false;
            }
        }

        class Carrier
        {
            public double PointX { get; set; }
            public double PointY { get; set; }
            public string Comment { get; set; }

            public Carrier(byte[] bytes)
            {
                string[] tmpStrings = Encoding.ASCII.GetString(bytes)
                    .Split('|');

                PointX = Convert.ToDouble(tmpStrings[0]);
                PointY = Convert.ToDouble(tmpStrings[1]);
                Comment = tmpStrings[2];
            }
        }
    }

Client

class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Client";

            IPEndPoint EP = new IPEndPoint(
                    IPAddress.Parse("192.168.1.100"), 4000
                    );

            TcpClient cli = new TcpClient();
            cli.Connect(EP);
            if (!cli.Connected)
            {
                Console.WriteLine("Not connected!");
                return;
            }
            Console.WriteLine("Connected!");
            NetworkStream ns = cli.GetStream();

            if (Authenticate(cli, ns))
            {
                Console.WriteLine("Good!");
                // This condition is met
            }
            else
            {
                Console.WriteLine("Bad!");
                return;
            }

            // Send data to server
            Carrier carrier = new Carrier();
            string stringtosend = carrier.ToString();
            byte[] bytestosend = Encoding.ASCII.GetBytes(stringtosend);
            ns.Write(bytestosend, 0, bytestosend.Length);

            Console.WriteLine("Data sent!");
            Console.ReadLine();

        }

        private static void UseClient(TcpClient cli, NetworkStream ns)
        {
            Console.WriteLine(ns.CanRead);
        }

        private static bool Authenticate(TcpClient client, NetworkStream ns)
        {
            //return true;
            byte[] rcv = new byte[1];
            while (!ns.DataAvailable)
            {
                Thread.Sleep(10);
            }

            int br = ns.Read(rcv, 0, rcv.Length);
            int ircv = rcv[0];
            int result = ircv * 3;
            byte[] snd = BitConverter.GetBytes(result);
            ns.Write(snd, 0, snd.Length);

            while (!ns.DataAvailable)
            {
                Thread.Sleep(10);
            }

            br = ns.Read(rcv, 0, rcv.Length);

            int iok = rcv[0];
            if (iok == 1)
            {
                return true;
            }
            return false;
        }
    }

    class Carrier
    {
        public double PointX { get; set; }
        public double PointY { get; set; }
        public string Comment { get; set; }


        public Carrier()
        {
            PointX = 1.00;
            PointY = 2.00;
            Comment = "A longer comment string";
        }

        public override string ToString()
        {
            return PointX.ToString() + "|"
                + PointY.ToString() + "|"
                + Comment;
        }
    }

So as I suspected, the problem was in the Authenticate method on the client side. I was sending an int instead of a single byte. The offending line of code was.

byte[] snd = BitConverter.GetBytes(result);

Which should have been.

byte[] snd = new byte[1] { (byte)result };

Thanks jdweng for finding the error.

PS, thanks to the down-voters for your interest, please accept my sincere pity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM