none
асинхронный сервер форма висит RRS feed

  • Вопрос

  • Здравствуйте.

    я новичок в c#.

    мне нужно написать клиент/серверное приложение.

    клиенты буду висеть на машинах и ожидать команд от сервера..

    пример взял от сюда http://msdn.microsoft.com/ru-ru/library/fx6588te.aspx

    это асинхронный сервер.

    при выполнении кода форма зависает и я не могу с сервера передавать команды.

    как я понял нужно сделать в разных потоках?

    подскажите как мне это сделать ?

    Спасибо.

    • Перемещено Tagore Bandlamudi 1 октября 2010 г. 21:37 MSDN Forums consolidation (От:Visual C#)
    7 августа 2010 г. 13:57

Ответы

  •   /// <summary>
      /// Поток сервера.
      /// </summary>
      public Thread ServerThread { }
    
      /// <summary>
      /// Старт сервера.
      /// </summary>
      public void Start()
      {
        ServerThread = new Thread(Work);
        ServerThread.Name = "Server thread";
        ServerThread.Start();
      }
    
      /// <summary>
      /// Рабочее тело сервера.
      /// </summary>
      public void Work()
      {
        // Тут код сервера, который должен работать в фоновом режиме
        ...
      }

    Work - это метод, где крутится непосредственно серверная часть.

    Таким образом мы из формы запускаем сервер в отдельном потоке.

    • Помечено в качестве ответа I.Vorontsov 25 августа 2010 г. 8:11
    7 августа 2010 г. 20:14

Все ответы

  •   /// <summary>
      /// Поток сервера.
      /// </summary>
      public Thread ServerThread { }
    
      /// <summary>
      /// Старт сервера.
      /// </summary>
      public void Start()
      {
        ServerThread = new Thread(Work);
        ServerThread.Name = "Server thread";
        ServerThread.Start();
      }
    
      /// <summary>
      /// Рабочее тело сервера.
      /// </summary>
      public void Work()
      {
        // Тут код сервера, который должен работать в фоновом режиме
        ...
      }

    Work - это метод, где крутится непосредственно серверная часть.

    Таким образом мы из формы запускаем сервер в отдельном потоке.

    • Помечено в качестве ответа I.Vorontsov 25 августа 2010 г. 8:11
    7 августа 2010 г. 20:14
  • Спасибо за ответ.

    С потоком разобрался теперь проблема в передачи из потока.

    т.е. вылазит исключение: "System.InvalidOperationException was unhandled

      Message=Cross-thread operation not valid: Control 'richTextBox1' accessed from a thread other than the thread it was created on.

      Source=System.Windows.Forms.."

     

    как я понял поток не знает что я хочу передать

    советуют использовать invoke.

    Подскажите как правильно его использовать?

    вот код мой:

       public partial class Form1 : Form

        {

            private Thread trd;

            // Incoming data from the client.

            public static string data = null;

            public void StartListening()

            {

                // Data buffer for incoming data.

                byte[] bytes = new Byte[1024];

     

                // Establish the local endpoint for the socket.

                // Dns.GetHostName returns the name of the 

                // host running the application.

                IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());

                IPAddress ipAddress = ipHostInfo.AddressList[1];

                IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);

                richTextBox1.AppendText("Сервер доступен по адресу: "+ipAddress);

                // Create a TCP/IP socket.

                Socket listener = new Socket(AddressFamily.InterNetwork,

                    SocketType.Stream, ProtocolType.Tcp);

                try

                {

                    listener.Bind(localEndPoint);

                    listener.Listen(10);

     

                    // Start listening for connections.

                    while (true)

                    {

                        richTextBox1.AppendText("Жду соединений...");

                        // Program is suspended while waiting for an incoming connection.

                        Socket handler = listener.Accept();

                        data = null;

     

                        // An incoming connection needs to be processed.

                        while (true)

                        {

                            bytes = new byte[1024];

                            int bytesRec = handler.Receive(bytes);

                            data += Encoding.ASCII.GetString(bytes, 0, bytesRec);

                            if (data.IndexOf("<END>") > -1)

                            {

                                break;

                            }

                        }

     

                        // Show the data on the console.

                        richTextBox1.AppendText("Данные : "+ data);

     

                        // Echo the data back to the client.

                        byte[] msg = Encoding.ASCII.GetBytes(data);

     

                        handler.Send(msg);

                        handler.Shutdown(SocketShutdown.Both);

                        handler.Close();

                    }

     

                }

                catch (Exception e)

                {

                    Console.WriteLine(e.ToString());

                }

                richTextBox1.AppendText("\nOk...");

                   }

     

     

            public Form1()

            {

                InitializeComponent();

            }

     

            private void btn_on_server_Click(object sender, EventArgs e)

            {

                Thread trd=new Thread(StartListening);

                trd.IsBackground = true;

                trd.Start();

            }

        }

    7 августа 2010 г. 20:52
  • вообще для таких целей может использовать BackgroundWorker?
    7 августа 2010 г. 20:56
  • вообще для таких целей может использовать BackgroundWorker?
    Возможно. Но я его ниразу не использовал. Предпочитаю минимум компонентов. Так код более наглядный и сразу видно все что происходит.
    7 августа 2010 г. 21:25
  • Попробуй перед 

    Thread trd=new Thread(StartListening);
    
    trd.IsBackground = true;
    
    trd.Start();

    добавить

    Control.CheckForIllegalCrossThreadCalls = false;

    Когда из одного потока ты пытаешься обратиться к свойствам или методам объекта, созданного не в данном потоке, то это может привести к непредсказуемым результатам, поэтому обычно выбрасывается исключение, которое ты и увидел в своем случае. 

    Данная строка отключит перехват исключений при межпотоковом взаимодействии.

     

    7 августа 2010 г. 21:33
  • Control.CheckForIllegalCrossThreadCalls = false;

    Когда из одного потока ты пытаешься обратиться к свойствам или методам объекта, созданного не в данном потоке, то это может привести к непредсказуемым результатам, поэтому обычно выбрасывается исключение, которое ты и увидел в своем случае.

    Данная строка отключит перехват исключений при межпотоковом взаимодействии.

    Отключение проверки исключений не очень хорошая затея, как сами и написали "это может привести к непредсказуемым результатам". Хотя, если tomkad сможет (знает как) проверять эту ошибку самостоятельно, то как вариант сгодится (но зачем ???). А без проверки это будет приводить к багам.

     

    tomkad:

    Посмотрите мой ответ в этой теме: http://social.msdn.microsoft.com/Forums/ru-RU/csharpru/thread/bb67c0cd-a6a9-47fe-9d4d-309f972897c1

    Ваше решение будет аналогичным.

     

    7 августа 2010 г. 23:38
  • Ну например, если ты просто выводишь на форму какие нибудь данные из другого потока, то ничего страшного произойти точно не может, и перехват исключений можно спокойно отключить. НО только при подобных действиях.

    И в контроле, в который ты будешь выводить данные, нужно запретить редактирование и любое изменение данных. Другими словами, сделать только для просмотра.

    А опасный блок кода поместить в конструкцию (вот тут про эту конструкцию можно почитать):

    try

    {

        // вывод данных на форму 

    }

    catch(Exception e)

    {

        MessageBox.Show("Приложение или объект, вызвавший исключение: " + e.Source + "\n\n" +

                                    "Метод, вызвавший исключение: " + e.TargetSite + "\n\n" +

                                    "Сообщение исключения: " + e.Message,

                                    "Исключение");

    }

    Я думаю этого будет достаточно. И выглядит понятнее для новичка, чем разбираться с делегатами.

    В идеале, конечно, делать так, как показано в том примере.

    8 августа 2010 г. 8:48
  • Ну если для новичка, тогда уж лучше использовать BackgroundWorker, тут подробно: http://rsdn.ru/article/dotnet/CSThreading2.xml

     

    Svyatoslav Pankratov, не хочу обидеть (честно), но, таким образом проверять на ошибки в межпоточных вызовах вы не сможете. Т.к. в данной конструкцие (try) все прокатит (т.к. , опять же, отключена проверка на межпоточные вызовы), а в дальнейшем (возможно в самом контроле, а может еще черт знает где (это и есть непредсказуемость)) выплывет ошибка, которая приведет (чаще всего) к вылету приложения и которую действительно поймать практически невозможно. И нет разницы, изменили вы просто текст в контроле или изменили чего-то глобальное. И = > с вашем решением у новичка намного больше будет головной боли.

    8 августа 2010 г. 12:20
  • Спасибо за замечания и исправления =) Обижаться не на что =) Если кто-то (и я в том числе) не прав, то исправляйте и предлагайте правильные решения =) Так и должно быть. В дальнейшем люди будут знать не только ответ на вопрос, а так же как делать не надо, и не допустят какой-нибудь серьезной ошибки из-за своего "пробела". Благодаря этому мы и учимся.
    8 августа 2010 г. 14:49
  • Обращение к Формам из других потоков действительно ни к чему страшному привести не может. Если не считать полного зависания приложения время от времени конечно.
    This posting is provided "AS IS" with no warranties, and confers no rights.
    8 августа 2010 г. 18:31
    Модератор