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

时间:2010-10-12 07:54:44

标签: c# multithreading networking tcp

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

如果您需要,请输入以下代码:

(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();
        }
    }
}

感谢-你,
特里斯坦!

2 个答案:

答案 0 :(得分:2)

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

catch
{
    //Connections--;
    break;
}

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

在频谱的另一端,Wireshark应该可以帮助您确定数据是否正在发送。

答案 1 :(得分:1)

我还没有仔细查看过您的代码,但是快速浏览后,您可以从多个线程访问变量而无需正确锁定。像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(...)调用设置属性的方法。