C # TcpClient не отправляет или читает 100% данных? - PullRequest
0 голосов
/ 12 октября 2010

Привет всем. Я пишу простое клиент-серверное приложение (просто для опыта, сеть для меня довольно новая), где клиент отправляет данные сервера, а сервер выводит их в текстовое поле. Все работает нормально, за исключением одной маленькой детали ... Кажется, иногда устанавливается соединение, но данные не отправляются и не читаются (не может решить, какие), и, следовательно, в текстовом поле ничего не выводится. Каждый раз, когда устанавливается соединение, счетчик увеличивается, то же самое происходит при получении блока данных. Когда вы сравниваете их, количество соединений корректное, но счетчик данных обычно меньше, иногда вдвое. В любом случае, если кто-нибудь может дать мне какой-нибудь совет или указать мне правильное направление, это будет с благодарностью!

Вот код, если он вам нужен:

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

2 голосов
/ 12 октября 2010

Ну, для начала вы наносите вред своей собственной диагностике с помощью этого:

catch
{
    //Connections--;
    break;
}

Почему вы глотаете исключения без любого ведения журнала и т. Д.? Может быть, выдается исключение, и у вас нет возможности узнать. В идеале вы должны ловить определенные исключения, а когда вы делаете ловите исключение как минимум регистрируйте происходящее.

На другом конце спектра Wireshark должен помочь вам определить, отправляются данные или нет.

1 голос
/ 12 октября 2010

Я еще не полностью изучил ваш код, но после быстрого просмотра вы получаете доступ к переменным из нескольких потоков без надлежащей блокировки.Оператор типа 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 (...) для вызова метода, который устанавливает свойство.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...