ФорумПрограммированиеБольше языковC/C++ и C# → C# №3: Работа с сетью. Sockets.

C# №3: Работа с сетью. Sockets.

  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 15 августа 2009 г. 14:32, спустя 35 дней 7 часов 18 минут

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

    http://frozzeg.no-ip.info/screens/screen_183_351940399.jpg

    Задача сервера: принимать входящие соединения и пакеты (координаты точки, в которой нужно рисовать) от клиентов и разсылать эти координаты всем клиентам, подключенным к серверу.
    Задача клиента: при попытке что либо нарисовать, сначала отправляем данные серверу, затем, если отправка прошла успешно - принимать координаты и нарисовать в указанном месте черную точку.



    Написание сервера.

    Подключаем нужные библиотеки
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;


    Инициализация переменных

           // Здесь будет хранится статус сервера
           bool isServerRunning;
           // Здесь будет список наших клиентов
           private Hashtable clients;
           // Это сокет нашего сервера
           Socket listener;
           // Порт, на котором будем прослушивать входящие соединения
           int port = 1991;
           // Точка для прослушки входящих соединений (состоит из адреса и порта)
           IPEndPoint Point;
           // Список потоков
           private List<Thread> threads = new List<Thread>();


    ЗНачинаем слушать входящие соединения
    private void ServerStart()
           {
               clients = new Hashtable(30);
               isServerRunning = true;
               listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
               // Определяем конечную точку, IPAddress.Any означает что наш сервер будет принимать входящие соединения с любых адресов
               Point = new IPEndPoint(IPAddress.Any, port);
               // Связываем сокет с конечной точкой
               listener.Bind(Point);
               // Начинаем слушать входящие соединения
               listener.Listen(10);

               SocketAccepter();
           }


    Обрабатываем входящие соединения
    private void SocketAccepter()
           {
               // Запускаем цикл в отдельном потоке, чтобы приложение не зависло
               Thread th = new Thread(delegate()
                   {
                       while (isServerRunning)
                       {
                           // Создаем новый сокет, по которому мы сможем обращаться клиенту
                           // Этот цикл остановится, пока какой-нибудь клиент не попытается присоединиться к серверу
                           Socket client = listener.Accept();
                           // Теперь, обратившись к объекту client, мы сможем отсылать и принимать пакеты от последнего подключившегося пользователя.
                           // Добавляем подключенного клиента в список всех клиентов, для дальнейшей массовой рассылки пакетов
                           clients.Add(client, "");
                           // Начинаем принимать входящие пакеты
                           Thread thh = new Thread(delegate()
                                                          {
                                                              MessageReceiver(client);
                                                          });
                           thh.Start();
                       }
                   });
               // Приведенный выше цикл пока что не работает, запускаем поток. Теперь цикл работает.
               th.Start();
               threads.Add(th);
           }


    Метод приема пакетов
    private void MessageReceiver(Socket r_client)
           {
               // Для каждого нового подключения, будет создан свой поток для приема пакетов
               Thread th = new Thread(delegate()
                   {
                       while (isServerRunning)
                       {
                           try
                           {
                                   // Сюда будем записывать принятые байты
                                   byte[] bytes = new byte[1024];
                                   // Принимаем
                                   r_client.Receive(bytes);
                                   if (bytes.Length != 0)
                                   {
                                       // Отсылаем принятый пакет от клиента всем клиентам
                                       foreach (Socket s_client in clients.Keys)
                                       {
                                           MessageSender(s_client, bytes);
                                       }
                                   }
                           }
                           catch {}
                       }
                   });
               th.Start();
               threads.Add(th);
           }


    Метод отправки пакетов

           private void MessageSender(Socket c_client, byte[] bytes)
           {
               try
               {
                   // Отправляем пакет
                   c_client.Send(bytes);

               }
               catch {}
           }




    Написание клиента.

    Подключаем библиотеки
    using System.Net;
    using System.Net.Sockets;
    using System.Threading;


    Инициализация переменных
    // Разрешено ли рисовать (т.е. если движение мыши осуществляется при нажатой клавише)
           private bool canDraw;
           // Статус клиента
           private bool client_running;
           // Сокет клиента
           private Socket client;
           // Адрес сервера
           private IPAddress ip = IPAddress.Parse("127.0.0.1");
           // Порт, по которому будем присоединяться
           private int port = 1991;
           // Список потоков
           private List<Thread> threads = new List<Thread>();


    Коннект к серверу
    void Connect()
           {
               try
               {
                   client_running = true;
                   client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                   client.Connect(ip, port);
                   Receiver();
               }
               catch { }
           }


    Метод, принимающий данные от сервера
    void Receiver()
           {
               Thread th = new Thread(delegate()
                                          {
                                              while (client_running)
                                              {
                                                  try
                                                  {
                                                      byte[] bytes = new byte[1024];
                                                      // Принимает данные от сервера в формате "X|Y"
                                                      client.Receive(bytes);
                                                      if (bytes.Length != 0)
                                                      {
                                                          string data = Encoding.UTF8.GetString(bytes);
                                                          string[] split_data = data.Split(new Char[] {'|'});
                                                          // Передаем отпарсенные значения методу Draw на отрисовку
                                                          Draw(Convert.ToInt32(split_data[0]),
                                                               Convert.ToInt32(split_data[1]));
                                                      }
                                                  }
                                                  catch {}
                                              }
                                          });
               th.Start();
               threads.Add(th);
           }


    Метод для отправки пакетов серверу
    void Sender(string msg)
           {
               try
               {
                   byte[] bytes = new byte[1024];
                   bytes = Encoding.UTF8.GetBytes(msg);
                   client.Send(bytes);
               }
               catch {}
           }


    Метод рисования
    void Draw(int x, int y)
           {
               try
               {
                   Graphics graphics = CreateGraphics();
                   graphics.FillEllipse(new SolidBrush(Color.Black), x, y, 5, 5);
               }
               catch {}
           }


    Остались пара событий, тут я думаю все итак понятно
    private void Form1_MouseDown(object sender, MouseEventArgs e)
           {
               canDraw = true;
           }

           private void Form1_MouseUp(object sender, MouseEventArgs e)
           {
               canDraw = false;
           }

           private void Form1_MouseMove(object sender, MouseEventArgs e)
           {
               if (canDraw)
               {
                   string asd = e.X.ToString() + "|" + e.Y.ToString();
                   // Посылаем данные серверу (координаты)
                   Sender(asd);
               }
           }

    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • phpdude

    Сообщения: 26617 Репутация: N Группа: в ухо

    Spritz 11 июля 2009 г. 4:05, спустя 13 часов 33 минуты 53 секунды

    ужасть))
    Сапожник без сапог
  • rider-sx

    Сообщения: 2717 Репутация: N Группа: Адекваты

    Spritz 11 июля 2009 г. 4:11, спустя 5 минут 26 секунд

  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 11 июля 2009 г. 4:21, спустя 10 минут 15 секунд


    ужасть))

    ага, просто показал сам принцип работы

    http://ridersx.no-ip.biz/scr/server.JPG
    Проблемка…

    поставь везде в коде try catch блоки
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • phpdude

    Сообщения: 26617 Репутация: N Группа: в ухо

    Spritz 11 июля 2009 г. 4:22, спустя 30 секунд


    http://ridersx.no-ip.biz/scr/server.JPG
    Проблемка…
    нажми дебаг а не билд и посмотри чо получится :) {+++21+++} f5, ане сеrl + f5
    Сапожник без сапог
  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 11 июля 2009 г. 4:25, спустя 3 минуты 42 секунды

    или так) кстати - вечная проблема
    у меня всегда все работает, а когда кому-нить кидаешь вечно приходится баги исправлять
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • rider-sx

    Сообщения: 2717 Репутация: N Группа: Адекваты

    Spritz 11 июля 2009 г. 4:29, спустя 3 минуты 56 секунд

    Странно… но при дебаге говорит что все нормульно все работает… а контрл+ф5 жму вылезает ошибка…
    Frozzeg, Я нуб, совсем нуб в этом вопросе, так что не понял я что и куда вставлять ) {+++100+++} попробовал запустить все это дело из скачанных примеров, запустил сервер, потом 2 клиента, в одном рисую все рисуется появдяется, но во 2 клиенте нет =) Может поправить ччего надобно ? м?
  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 11 июля 2009 г. 4:30, спустя 34 секунды

    Хм, попробуй зайти в Меню - Build - Cinfguration Manager - Configuration и поставь там Release
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • phpdude

    Сообщения: 26617 Репутация: N Группа: в ухо

    Spritz 11 июля 2009 г. 4:33, спустя 3 минуты 25 секунд


    Хм, попробуй зайти в Меню - Build - Cinfguration Manager - Configuration и поставь там Release
    думаю что проблема с тредингом.

    во вторых - прикольная технология взаимодействия .net => .net = Remoting. есть чо рассказать по ней?
    Сапожник без сапог
  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 11 июля 2009 г. 4:40, спустя 6 минут 53 секунды

    rider-sx, Попробуй написать заного все самому, опираясь на мой код и документацию по используемым классам {+++82+++}


    Хм, попробуй зайти в Меню - Build - Cinfguration Manager - Configuration и поставь там Release
    думаю что проблема с тредингом.

    во вторых - прикольная технология взаимодействия .net => .net = Remoting. есть чо рассказать по ней?
    не юзал никогда {+++258+++} rider-sx, обновил исходники, попробуй щас
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • rider-sx

    Сообщения: 2717 Репутация: N Группа: Адекваты

    Spritz 11 июля 2009 г. 6:19, спустя 1 час 38 минут 56 секунд

    Frozzeg, щас попробую
    {+++748+++} Во! Айс ))) Все гут и работает ) Спасибо ;) {+++911+++} Это наверно не столь важно но все же ))) http://ridersx.no-ip.biz/scr/format.JPG
    Я так понял что данные не в той форме принимаются которая нужна методу Draw? {+++226+++} Frozzeg, Еще можешь выложить инсталятор XNA Game Studio на своем серве, а то винду переустанавливать как то не прет ;)
  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 11 июля 2009 г. 6:47, спустя 28 минут 24 секунды

    данные для всех форм одни и те же, щас выложу {+++197+++} http://frozzeg.no-ip.info/XNAGS30_setup.rar
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • rider-sx

    Сообщения: 2717 Репутация: N Группа: Адекваты

    Spritz 11 июля 2009 г. 7:00, спустя 12 минут 58 секунд

    Frozzeg, спасибо =) скачаю попробую чтонить по туторам на их сайте заделать )
  • Frozzeg

    Сообщения: 5642 Репутация: N Группа: Джедаи

    Spritz 11 июля 2009 г. 7:10, спустя 9 минут 26 секунд

    рановато ты за ХНА взялся, сначало изучи специфику языка

    з.ы. http://xnadev.ru/news.php
    You can be anything you want to be. Just turn yourself into anything you think that you could ever be.
  • rider-sx

    Сообщения: 2717 Репутация: N Группа: Адекваты

    Spritz 11 июля 2009 г. 7:13, спустя 3 минуты 6 секунд


    рановато ты за ХНА взялся, сначало изучи специфику языка

    з.ы. http://xnadev.ru/news.php
    Возможно =) Ну по крайней мере мне вполне понятны туторы на которые там )

Пожалуйста, авторизуйтесь, чтобы написать комментарий!