Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как привзять TcpListener к конретному удалённому 
:(
    Опции темы
artstalker
Дата 6.3.2009, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



Мне надо принимать только пакеты от конкретного удалённого компа. Мне известен его ип. Как сделать, чтобы TcpListener слушал только конкретную удалённую станцию?
PM MAIL   Вверх
-Mikle-
Дата 6.3.2009, 20:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Если я еще не совсем потерял бдительность, то TcpListener слушает порт на "своем" компе, а не удаленные компы в принципе.
Тебе надо просто проверять адрес подключившегося компа и убивать его сокет, если адрес не тот который тебе нужен...


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
artstalker
Дата 6.3.2009, 21:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



TcpListener слушает на своём компе порт, но на этот порт приходят же пакеты с разных ip. Чтобы проверить адрес, мне надо начать слушать его, а для меня это не подходит. Мне нужно изначально гарантированно принимать только с одного ip
PM MAIL   Вверх
-Mikle-
Дата 6.3.2009, 21:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Цитата(artstalker @  7.3.2009,  00:12 Найти цитируемый пост)
но на этот порт приходят же пакеты с разных ip

Ну во первых, сначала приходят не пакеты, а запросы на соединение. Во вторых, с каких разных? Ты же ведь будешь слушать свой порт, например 2099, чтобы туда пришел запрос на соединение, кто-то должен конкретно указать адрес твоего компа и порт (2099) как минимум. Это конечно может иметь непредвиденный характер, но таковых запросов будет не так много я полагаю. Да и даже пусть приходят, что с этого? Не разрешай им и все... Что именно тебя не устраивает?

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


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
artstalker
Дата 6.3.2009, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



Всё дело в том, что моё приложение предусматривает параллельный приём данных сразу с нескольких удалённых станций. Т.е. я создаю необходимое число TcpListener-ов в параллельных потоках и слушаю один и тот же порт. Если я не смогу как-то соединить каждый TcpListener  с конкретным ip, то каша получится  smile  .
А почему в С++ в сервисе WinSock мы можем слушать с конкретного ip? Тут нет такого аналога?

Это сообщение отредактировал(а) artstalker - 6.3.2009, 21:46
PM MAIL   Вверх
-Mikle-
Дата 6.3.2009, 23:15 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Цитата(artstalker @  7.3.2009,  00:45 Найти цитируемый пост)
А почему в С++ в сервисе WinSock мы можем слушать с конкретного ip?

Я не знаю точно, может быть там низкоуровневая реализация есть, которая отклоняет конекты.

А по сабжу, теперь мне все ясно стало.
Болезнь: Ты запутался в том, как все это работает.
Лекарство:
Всегда, всегда только один Socket может слушать какой-то порт. Когда необходимо принимать подключения, то создается слушающий сокет. При наличии в очереди запроса на соединение, слушающий сокет поступает следующим образом:
1. создает новый сокет;
2. присваивает ему какой-нибудь свободный порт;
3. возвращает тебе вновь созданный Socket;
4. продолжает слушать дальше.

Все! Теперь у тебя есть эксклюзивный сокет с клиентом. Далее ты можешь проверить IP и закрыть его, если он не твой. Для теста, ты можешь дебагом посмотреть номер порта этого сокета, чтобы убедиться, что я не соврал тебе насчет номера порта, отличающегося от того, на котором ты слушаешь.

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

Теперь немного кода. Ради примера, я не делал никаких потоков, а использовал таймер:

Код

        TcpListener tcpListener;
        Dictionary<IPAddress, TcpClient> clients;

        private void Start()
        {
            clients = new Dictionary<IPAddress, TcpClient>();
            tcpListener = new TcpListener(IPAddress.Any, 2099);
            tcpListener.Start();
        }

        private void Stop()
        {
            tcpListener.Stop();
            foreach (TcpClient client in clients.Values)
            {
                client.Client.Disconnect(false);
                client.Client.Close();
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            while (tcpListener.Pending())
            {
                IPEndPoint d;

                TcpClient client = tcpListener.AcceptTcpClient();
                IPAddress remoteIP = ((IPEndPoint)client.Client.RemoteEndPoint).Address;

                // запретить локально подключаться!!!
                if (remoteIP == IPAddress.Parse("127.0.0.1"))
                {
                    client.Client.Disconnect(false);
                    client.Client.Close();
                    continue;
                }

                clients.Add(remoteIP, client);
            }
        }


У меня был достаточно большой и достаточно сложный проект, в котором я поимел определенный опыт. Будь осторожен с многопоточностью. Если у тебя будет 200 клиентов, то создавать 200 потоков для каждого - это очень плохо кончится... Обращайся.


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
artstalker
Дата 7.3.2009, 02:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



Спасибо за консультацию, теперь я начинаю понимать.
У меня к тебе пару вопросов:
1. while (tcpListener.Pending())
            {}
Как я понял это цикл в котором обрабатываются все запросы на подключение, после того как они обработаются цикл завершится?
Просто я использую бесконечный цикл, т.к. мне надо всегда слушать порт. Может есть какой-то другой вариант..
2.У меня не так много клиентов могут подключаться одновременно. Ну пусть будет максимум 5 штук. Может проще создать 5 TcpListener-ов в параллельных потоках и слушать 5 разных портов для каждого клиента? (это я к чему. я так понял что нельзя в параллельных потоках слушать один и тот же порт)


Это сообщение отредактировал(а) artstalker - 7.3.2009, 02:39
PM MAIL   Вверх
-Mikle-
Дата 7.3.2009, 11:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Цитата(artstalker @  7.3.2009,  05:39 Найти цитируемый пост)
Как я понял это цикл в котором обрабатываются все запросы на подключение, после того как они обработаются цикл завершится?

Да, именно так, но он снова запустится по таймеру. Забыл что ф-ия в таймере? Если никого не будет в очереди, то цикл завершится. Потом снова. Я для простоты примера так сделал, без потоков...

Цитата(artstalker @  7.3.2009,  05:39 Найти цитируемый пост)
Просто я использую бесконечный цикл, т.к. мне надо всегда слушать порт. Может есть какой-то другой вариант..

На сегодня других вариантов не предоставлено. Оптимально будет для этой цели сделать трединговый таймер, он использует пул потоков, вместо создания нового.

Цитата(artstalker @  7.3.2009,  05:39 Найти цитируемый пост)
Может проще создать 5 TcpListener-ов в параллельных потоках и слушать 5 разных портов для каждого клиента?

Нет, так делать не нужно. Во первых, это будет сложнее для клиентов. Они как-то должны будут еще узнать, к какому порту им подключаться. А если клиентов завтра станет шесть? Или 200? Нет, так никто не делает, потому что это не проще, а сложнее. Слушать надо только один сокет (можно в отдельном потоке), а вот обрабатывать прием/передачу отдельного сокета можно в отдельном потоке. Но не по принципу один сокет - один поток! Для начала, можно и по одному потоку на сокет, но потом обязательно переделать и реализовать динамический пул, где будет приниматься решение о необходимости создания нового потока для обработки принятых данных. Но об этом потом.

Я и другие форумчане уже где-то отвечали на подобные вопросы, но мне не лень еще раз повториться.
Я уже создал у себя новый проект и назвал его "artstalker". В нем я буду писать вместе с тобой.
Вот тебе для начала простая архитектура, которую, мы постараемся довести постепенно до приемлемого уровня.
Итак:
1. Имеется класс ClientManager. Он будет самым главным. В его задачи входит следующее:
    а) он создает и управляет работой TcpListener, который обрабатывает очередь запросов на подключение в отдельном потоке;
    б) он должен имееть поле, список подключенных клиентов. Лучше сделать словарь (Dictionary), в котором ключем будет IPAddres, а значением TcpClient. После обработки запроса на подключение в этот список добавляется клиент TcpClient. Этот список будет активно использоваться. Еще мы потом сделаем свою обертку для TcpClient (или Socket, посмотрим еще потом) и будем добавлять в список клиентов уже его, а не TcpClient;
    в) этот класс должен иметь методы Start(IPAddress listenAddress, int port) и Stop(), которые начинают и завершают его работу;
    г) должен быть метод Send(IPAddress clientIP, byte[] data) и Send(IPAddress clientIP, string data). Можно сделать оба или один из них, в зависимости от того, что ты планируешь посылать;
    д) событие Disconnect, которое будет вызываться если один из клиентов отвалится. В качестве параметра надо передать IPAddress отвалившегося клиента;
    е) событие ReciveDataReady, которое будет вызываться, когда данные от какого-то клиента будут готовы для обработки. В качестве параметра надо передать IPAddress клиента от которого готовы данные и сами данные.

Для начала хватит. Можешь пока сделать только шаблон класса, то есть не наполнять его методы функциональностью. Объяви сам класс, необходимые поля в нем, методы, классы DisconectEventArgs и ReciveDataReadyEventArgs с нужными свойствами и делегаты для наших событий. Выкладывай все сюда, потом будем продолжать.


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
-Mikle-
Дата 7.3.2009, 15:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Чтоб силно не заморачиваться, вот клиент, которым будем проверять наш сервер. Не проверял на практике (т.к. пока нет сервера никакого), но вроде должен работать... Потом потестируем...



Присоединённый файл ( Кол-во скачиваний: 9 )
Присоединённый файл  ArtstalkerClient.rar 11,30 Kb


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
artstalker
Дата 7.3.2009, 15:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



Хорошо, сейчас начну писать. Давай я тогда подробнее опишу задачу и как я это вижу(и собственно как уже реализовал smile ). На данный момент это приложение(приложения), которое стоит на машинах в одной сети и может передавать/принимать файлы.
Как я это вижу:
1. В приложении есть фоновый поток, который постоянно слушает порт (50174). Если к нему приходит сообщение от какого-то клиента в котом написано "#Transfer:имя_файла", то
2 Я определяю ip с которого пришло сообщение
3 Создаю новое окно в котором клиент может либо разрешить приём файла, либо запретить. В любом случае от исхода я посылаю ответ по порту 50173(т.к. 50174 должен всегда слушать, в этот момент может прийти очередной запрос на приём файла). 
4 Если пользователь согласился на приём файла, то я посылаю сообщение с маркировкой "#Yes" по порту 50173(кстати тут можно было бы указать и порт на котторый будет передавать файл, но как я понял это плохой выход).
 5. Начинаю слушать порт 50175(это и есть транспортный порт)
6. Удалённый компьютер прочитав по порту 50173 "#Yes" начинает отсылку файла на 50175

Собственно вчера уже реализовал, работает, но только 1 клиент - 1 сервер и немного коряво(без классов) 
С твоей помощью сейчас начну заново писать. Ближе к вечеру выложу класс, который ты описал

Это сообщение отредактировал(а) artstalker - 7.3.2009, 15:19
PM MAIL   Вверх
-Mikle-
Дата 7.3.2009, 18:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Задача ясна, но видишь ты ее себе слишком запутанно. smile 
Все намного проще - три порта не понадобятся, только один. Потом все поймешь, обещаю постараться!  smile 
Ради достижения цели обучения, мы с тобой еще и собственный протокол обмена придумаем, постепенно, шаг за шагом.

Добавлено через 2 минуты и 32 секунды
Модераторам: Думаю ветку надо кинуть в "распределенные приложения и сеть"


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
artstalker
Дата 7.3.2009, 19:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 126
Регистрация: 5.2.2009

Репутация: нет
Всего: нет



Вот что я только что наваял

Код

 class DisconnectEventArgs
        {
            string info;
        }

        class ReciveDataReadyEventArgs
        {
            string info;
            string message;
            byte[] data;
        }

        struct adress
        {
           
            public IPAddress IP;
            public int port;
        }

        class ClientManager
        {
           
            TcpListener Listener;
            Dictionary<IPAddress, TcpClient> clients;
            Thread TreadListen;
            void BackgroundListening(object state)
            {
                
                adress temp = (adress)state;
                Listener = new TcpListener(temp.IP, temp.port);
                Listener.Start();
                while (true)
                {
                    TcpClient client = Listener.AcceptTcpClient();

                }

            }


            public delegate void DelegateDiconnect(object sender, DisconnectEventArgs e);
            public event DelegateDiconnect Disconnect;
            public delegate void DelegateReciveDataReady(object sender, ReciveDataReadyEventArgs e);
            public event DelegateReciveDataReady ReciveDataReady;
        
            
            public ClientManager (){}
            public void AddClient(TcpClient client) 
            {

                clients.Add(client.Client.RemoteEndPoint,client);/*Здесь несоответсвие типов RemoteEndPoint  и IPAddress*/
            }
            public  void Start(adress temp)
            {
                if (Listener != null) return;
                TreadListen = new Thread(BackgroundListening);
                TreadListen.IsBackground = true;
                TreadListen.Start(temp);
                
            }
            public void Stop() 
            {
                if (TreadListen == null) return;
                TreadListen.Abort();
            }
            public void Send(IPAddress clientIP, byte[] data) { }
            public void Send(IPAddress clientIP, string data) { }
           
           

        }

Я вот только не могу понять зачем при создании TcpListener  мы передаём IP?
Код

Listener = new TcpListener(IP, port);


Я раньше создавал так
Код

Listener = new TcpListener(port);


P.S. В данном случае мы реализовываем 2 отдельных приложения клиент и сервер. А мы сможем потом это объеденить в одно приложение? Суть в том, что каждое приложение может связываться со всеми другими


Это сообщение отредактировал(а) artstalker - 7.3.2009, 19:41
PM MAIL   Вверх
-Mikle-
Дата 7.3.2009, 21:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Невидимка Vingrad'а
***


Профиль
Группа: Экс. модератор
Сообщений: 1672
Регистрация: 22.6.2003
Где: Казахстан, Астана

Репутация: 1
Всего: 59



Цитата(artstalker @  7.3.2009,  22:40 Найти цитируемый пост)
clients.Add(client.Client.RemoteEndPoint,client);/*Здесь несоответсвие типов RemoteEndPoint  и IPAddress*/

Это потому, что он возвращает базовый тип EndPoint, а не IP-адрес.
Код

clients.Add(((IPEndPoint)client.Client.RemoteEndPoint).Address, client);


Цитата(artstalker @  7.3.2009,  22:40 Найти цитируемый пост)
 class DisconnectEventArgs
        {
            string info;
        }

Нужно наследовать от EventArgs и сделать нормальные события
Код

        public class DisconnectEventArgs : EventArgs
        {
            public DisconnectEventArgs(IPAddress clientIPAddr) { this.clientIP = clientIPAddr; }

            public IPAddress ClientIP { get { return clientIP; } }
            IPAddress clientIP;
        }

По такому же принципу сделай ReciveDataReadyEventArgs. Свойствами его наделять пока не будем.

Цитата(artstalker @  7.3.2009,  22:40 Найти цитируемый пост)
        struct adress
        {
           
            public IPAddress IP;
            public int port;
        }

Не нужна такая структура, такая уже существует: IPEndPoint

Цитата(artstalker @  7.3.2009,  22:40 Найти цитируемый пост)
Я вот только не могу понять зачем при создании TcpListener  мы передаём IP?

Потому что этот вариант конструктора будет убран в одной из следующих версий. Останется только два: (IPEndPoint) и (IPAddress, int)
Цитата(MSDN)
System.Net.Sockets.TcpListener.TcpListener(int) "This method has been deprecated. Please use TcpListener(IPAddress localaddr, int port) instead.


Цитата(artstalker @  7.3.2009,  22:40 Найти цитируемый пост)
P.S. В данном случае мы реализовываем 2 отдельных приложения клиент и сервер. А мы сможем потом это объеденить в одно приложение? Суть в том, что каждое приложение может связываться со всеми другими

Нет, не сможем. В данном случае мы пишем клиент-серверное приложение. Один сервер и много клиентов. Если сервер не доступен, клиенты не могут общаться между собой. Ты уж давай определяйся, а то мы уже начали с архитектуры клиент-серверного приложения.

И еще я тут подумал, что так у нас ничего не выйдет. Долго это будет и не все топики информативны. Предлагаю тебе перейти на ICQ, номер я тебе скинул в PM (в самом верху страницы форума есть ссылочка "1 новых писем"). Когда будешь соединяться, в сообщении напиши что это ты, а то тут спамеров, последнее время много. Мы с тобой по ICQ отработаем весь код, и потом сюда решающим топиком прикрепим то, что у нас получится. В аське я буду через час, в 22-00 (GMT+3, Москва).


--------------------
Если тебе плюют в спину, значит ты впереди...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
cully
mr.DUDA
Exception

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, cully, mr.DUDA, Exception.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Распределённые приложения и сеть | Следующая тема »


 




[ Время генерации скрипта: 0.0530 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.