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

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

  • Frozzeg

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

    Spritz 16 августа 2009 г. 1: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

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

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

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

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

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

  • Frozzeg

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

    Spritz 11 июля 2009 г. 15: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

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

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


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

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

    Spritz 11 июля 2009 г. 15: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

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

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

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

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

    Spritz 11 июля 2009 г. 15: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

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

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


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

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

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

    Spritz 11 июля 2009 г. 15: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

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

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

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

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

    Spritz 11 июля 2009 г. 17: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

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

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

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

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

    Spritz 11 июля 2009 г. 18: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

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

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


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

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

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