NetworkStream.Write 数据似乎没有到达接收套接字

Posted

技术标签:

【中文标题】NetworkStream.Write 数据似乎没有到达接收套接字【英文标题】:NetworkStream.Write data seems not to arrive at receiving socket 【发布时间】:2017-01-26 11:49:33 【问题描述】:

C# System.Net,套接字

我遇到了一个问题,我无法弄清楚我可能做错了什么。

故事是,我将 byte[] 应用程序数据从 TcpClient 套接字发送到另一个 TcpClient 套接字。这一切都很好,直到我在发送应用程序数据之前添加了一个自定义伪身份验证测试,之后最初工作的发送和接收失败。

我说失败,但实际发生的是它似乎只在读取套接字处将 3 个字节全部设置为 0。

Authenticate 方法执行以下操作。 服务器端发送1个字节的数据(0-85),客户端接收到,把它当作一个int,乘以3,发回一个字节给服务器。服务器检查该值,并将另一个字节返回设置为 1。

所有这些似乎都可以正常工作,但是似乎没有收到客户端在身份验证后发送的数据,只是将 3 个字节设置为 0。

我希望套接字在程序的整个生命周期内保持打开状态,因此我无法释放流,因为这也会释放套接字。

这是客户端和服务器的完整代码,希望有人能看到我的错误,或者我遗漏的问题。

为了简洁起见,代码故意不进行错误检查,并且非常基本地仅显示问题。

请注意,如果两个 Authenticate 方法都简单地返回 true,那么代码将完全按照我的预期工作。

服务器。

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];
            
        
    

客户

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;
        
    

【问题讨论】:

您的代码只是在发送一条消息后终止。您需要一个循环来阻止代码终止,这通常称为 BLOCK。您可以使用 WAITONE 来阻止。请参阅以下网页上的 msdn 异步示例:msdn.microsoft.com/en-us/library/w89fhyex(v=vs.110).aspx 注意:msdn 示例也会在几条消息后终止。 我的印象是 Console.ReadLine();保持代码存活。 是的,Readline 会阻塞,但您使用的是同步方法,并且您没有循环来处理多条消息。 我知道,同步是我想要的,你能解释一下循环将如何帮助解决我的问题吗?如果我什至无法成功发送,我认为我不需要循环来发送更多消息一。 有7个网络层。您的代码具有客户端和服务器的传输层。您缺少应用程序层。应用层客户端发送消息,服务器接收消息并处理消息,然后服务器发送响应。客户端收到响应,然后发送下一条消息。您的代码是否让客户端发送多条消息?您的服务器可以接收多条消息并回复每条消息吗? 【参考方案1】:

所以我怀疑,问题出在客户端的 Authenticate 方法中。 我发送的是 int 而不是单个字节。有问题的代码行是。

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

应该是这样的。

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

感谢 jdweng 发现错误。

PS,感谢投反对票的人的关注,请接受我诚挚的同情。

【讨论】:

以上是关于NetworkStream.Write 数据似乎没有到达接收套接字的主要内容,如果未能解决你的问题,请参考以下文章

设置一个新的 Cron 来运行一个 PHP 文件,但似乎啥也没发生

将 imageCollection 从 Google 地球引擎导入到 QGIS - 如果代码和 crs 似乎没问题,为啥地图不会出现在画布上?

Embedded Jetty HTTP/2 不适用于 Firefox/Chrome,但在 Safari 上似乎没问题

three.js控制台错误“scene.getObjectByName(...)未定义”但一切似乎都没问题?

AWS疯狂投入数据库 似乎不仅是为了干掉Oracle那么简单

新技术来了,你没必要继续折腾WebGL了!