C# TcpClient 未发送或读取 100% 的数据?

发布于 2024-09-27 16:59:48 字数 4188 浏览 3 评论 0原文

嘿大家。我正在编写一个简单的客户端/服务器应用程序(只是为了体验,网络对我来说相当新),其中客户端发送服务器数据,服务器将其输出到文本框。除了一个小细节之外,一切都工作正常......有时似乎建立了连接,但数据没有被发送或读取(无法弄清楚是哪个),因此文本框中没有输出任何内容。每次建立连接时,计数器都会递增,收到数据块时也是如此。当您比较两者时,连接数是正确的,但数据计数器通常较低,有时多达一半。无论如何,如果有人能给我一些建议或指出我正确的方向,我将不胜感激!

如果您需要,这里是代码:

(SERVER_CODE)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Server
{
    public partial class Form1 : Form
    {
        public int Connections = 0;
        public int blocks = 0;
        public int threads = 0;
        public Thread MasterThread;
        public TcpListener Master;
        public volatile bool Run;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        public void StartMaster()
        {
            Master = new TcpListener(IPAddress.Any, 1986);
            Master.Start();
            MasterThread = new Thread(new ThreadStart(RunMaster));
            MasterThread.Start();
        }

        public void RunMaster()
        {
            threads++;
            label6.Text = String.Format("{0}", threads);

            while (Run)
            {
                TcpClient client = Master.AcceptTcpClient();
                Connections++;
                label4.Text = String.Format("{0}", Connections);
                Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
                ClientThread.Start(client);
            }

            Master.Stop();

            threads--;
            label6.Text = String.Format("{0}", threads);
        }

        public void RunClient(object tcpClient)
        {
            TcpClient client = (TcpClient)tcpClient;
            byte[] buffer = new byte[4096];
            int byteCount = 0;
            NetworkStream stream = client.GetStream();
            threads++;
            label6.Text = String.Format("{0}", threads);

            while (Run)
            {
                try
                {
                    byteCount = stream.Read(buffer, 0, 4096);
                }
                catch
                {
                    //Connections--;
                    break;
                }

                if (byteCount == 0)
                {
                    //Connections--;
                    break;
                }

                blocks++;
                label5.Text = String.Format("{0}", blocks);

                textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
            }

            client.Close();

            threads--;
            label6.Text = String.Format("{0}", threads);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Run = true;
            StartMaster();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Run = false;
        }
    }
}

(CLIENT_CODE)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Client
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
            TcpClient client = new TcpClient();
            try
            {
                client.Connect(endPoint);
            }
            catch
            {
                MessageBox.Show("Connect Error");
            }

            NetworkStream stream = client.GetStream();
            byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
            stream.Write(data, 0, data.Length);
            stream.Flush();
            client.Close();
        }
    }
}

谢谢,
特里斯坦!

Hey all. I'm writing a simple client/server application (just for the experience, networking is fairly new to me) where the client sends the server data and the server outputs it to a textbox. It all works fine, except for one small detail... It seems sometimes a connection is made, but the data isn't being sent or read (can't work out which) and thus nothing is being outputted in the textbox. Every time a connection is made a counter is incremented, same thing when a data block is received. When you compare the two, the number of connections is correct but the data counter is usually lower, sometimes by as much as half. Anyway, if anyone can give me some advice or point me in the right direction, it would be greatly appreciated!

Here's the code if you require it:

(SERVER_CODE)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Server
{
    public partial class Form1 : Form
    {
        public int Connections = 0;
        public int blocks = 0;
        public int threads = 0;
        public Thread MasterThread;
        public TcpListener Master;
        public volatile bool Run;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        public void StartMaster()
        {
            Master = new TcpListener(IPAddress.Any, 1986);
            Master.Start();
            MasterThread = new Thread(new ThreadStart(RunMaster));
            MasterThread.Start();
        }

        public void RunMaster()
        {
            threads++;
            label6.Text = String.Format("{0}", threads);

            while (Run)
            {
                TcpClient client = Master.AcceptTcpClient();
                Connections++;
                label4.Text = String.Format("{0}", Connections);
                Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
                ClientThread.Start(client);
            }

            Master.Stop();

            threads--;
            label6.Text = String.Format("{0}", threads);
        }

        public void RunClient(object tcpClient)
        {
            TcpClient client = (TcpClient)tcpClient;
            byte[] buffer = new byte[4096];
            int byteCount = 0;
            NetworkStream stream = client.GetStream();
            threads++;
            label6.Text = String.Format("{0}", threads);

            while (Run)
            {
                try
                {
                    byteCount = stream.Read(buffer, 0, 4096);
                }
                catch
                {
                    //Connections--;
                    break;
                }

                if (byteCount == 0)
                {
                    //Connections--;
                    break;
                }

                blocks++;
                label5.Text = String.Format("{0}", blocks);

                textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
            }

            client.Close();

            threads--;
            label6.Text = String.Format("{0}", threads);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Run = true;
            StartMaster();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Run = false;
        }
    }
}

(CLIENT_CODE)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Client
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
            TcpClient client = new TcpClient();
            try
            {
                client.Connect(endPoint);
            }
            catch
            {
                MessageBox.Show("Connect Error");
            }

            NetworkStream stream = client.GetStream();
            byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
            stream.Write(data, 0, data.Length);
            stream.Flush();
            client.Close();
        }
    }
}

Thank-you,
Tristan!.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

欢你一世 2024-10-04 16:59:48

好吧,首先你会用这个来削弱你自己的诊断:

catch
{
    //Connections--;
    break;
}

为什么你要在没有任何日志记录的情况下吞掉异常?也许抛出了异常,而您无从得知。理想情况下,您应该捕获特定异常,并且当您确实捕获异常时至少记录正在发生的情况。

另一方面,Wireshark 应该可以帮助您确定数据是否正在发送。

Well, to start with you're crippling your own diagnostics with this:

catch
{
    //Connections--;
    break;
}

Why are you swallowing exceptions without any logging etc? Maybe an exception is being thrown, and you have no way of knowing. Ideally you should catch specific exceptions, and when you do catch an exception at least log what's going on.

At the other end of the spectrum, Wireshark should help you to work out whether the data is being sent or not.

鹿港巷口少年归 2024-10-04 16:59:48

我还没有彻底查看您的代码,但快速浏览后,您可以在没有适当锁定的情况下从多个线程访问变量。像 x++; 这样的语句必须读取 x 的值,递增它,然后将其写回。现在,如果您有两个线程执行此操作,您可能会遇到这种情况:

x = 0

Thread 1           Thread 2
------------------------
Read (0)
                   Read (0)
Increment (1)
                   Increment (1)
Write (1)
                   Write (1)

=> x = 1 instead of 2

如果您需要从多个线程访问变量,请始终同步,除非您确切知道自己在做什么。例如,创建并使用如下所示的同步对象:

int threads = 0;
object threadSync = new object();

...

lock (threadSync) {
    threads++;
}

那么一次只有一个线程可以访问该变量,并且值会正确递增。

编辑:另一个问题是您从与创建可见控件的线程不同的线程访问可见控件。早期的 .NET 版本允许这样做,但较新的版本不允许。如果需要更新状态消息,则需要查看控件的 InvokeRequired 属性,如果设置为 true,则使用 Control.Invoke(...) 调用设置该属性的方法。

I haven't had a thorough look at your code yet, but after a quick glance, you access variables from multiple threads without proper locking. A statement like x++; has to read the value of x, increment it, and write it back. Now if you have two threads doing this, you might run into this situation:

x = 0

Thread 1           Thread 2
------------------------
Read (0)
                   Read (0)
Increment (1)
                   Increment (1)
Write (1)
                   Write (1)

=> x = 1 instead of 2

If you need to access variables from multiple threads, ALWAYS synchronize unless you know exactly what you're doing. For example, create and use a synchronization object like this:

int threads = 0;
object threadSync = new object();

...

lock (threadSync) {
    threads++;
}

Then only one thread may access the variable at a time and values are incremented correctly.

Edit: Another problem is that you access visible controls from a different thread than the one that created them. Early .NET versions allowed this, but the newer don't. If you need to update status messages, you need to look at the control's InvokeRequired property and if set to true, use Control.Invoke(...) to call a method that sets the property.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文