Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: реализация TCP соединений на c#  (Прочитано 16583 раз)
0 Пользователей и 2 Гостей смотрят эту тему.
гайка
Гость
« : 18-07-2012 11:47 » 

Товарищи, кто мне может объяснить, почему к объекту Socket нельзя подключиться в обычном (синхронном) режиме, если соединение было разорвано? или если первая попытка подключения была безуспешной.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #1 : 18-07-2012 14:37 » 

Гайка, непонятно, что значит "подключиться в синхронном режиме"? Либо сам сокет подключается к чему-то на другой стороне, либо он принимает чьё-то соединение с другой стороны.

Код, который не работает, сюда.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
гайка
Гость
« Ответ #2 : 20-07-2012 09:08 » 

Да, прости, я неправильно сказала. не "подключиться", а "подключить".
у  Socket есть 2 способа подключения:
1) метод Connect, он работает в текущем потоке и, если порт недоступен, по истечению таймаута выдает исключение
2) метод BeginConnect, он работает в другом потоке и по завершению работы возвращается к текущему потоку, а именно к тому методу, который указан в параметре. да, я сама знаю, что я кэп.
так вот, если порт доступен, то подключение выполняется нормально. а если порт становится недоступным (в моем случае, если вытаскивается из розетки устройство, открывающее tcp порты) на какое-то время, а потом снова открывается, то доступ к нему уже не получить ни одним из этих методов.

и да, в моем случае, сокет только сам подключается к чему-то, но не принемает входящие подключения.

код бы нежелательно выкладывать, это рабочий проект.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 20-07-2012 10:56 » 

Цитата: Гайка
код бы нежелательно выкладывать, это рабочий проект.
У меня правило все такие сомнительные вещи отрабатывать на небольших прототипах - консольных программках, и только потом переносить отлаженный код в рабочий проект.

А так беспредметно говорим. Если посмотреть MSDN для BeginConnect, там такая масса ньюансов, что без кода гадать бесполезно.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
гайка
Гость
« Ответ #4 : 20-07-2012 13:01 » 

Код: (C#)
    public class Base : Singleton<Base>
    {
        List<Gateway> _gateways;//список шлюзов
        public List<Gateway> Gateways
        {
            get { return _gateways; }
            set { _gateways = value; }
        }

        List<TCPConnection> _connections;//список всех подключений
        public List<TCPConnection> Connections
        {
            get { return _connections; }
            set { _connections = value; }
        }

        static int _refreshingInterval = 7000;//интервал обновления соединения
        public static int RefreshingInterval
        {
            get { return Base._refreshingInterval; }
            set { Base._refreshingInterval = value; }
        }

        System.Timers.Timer _refreshingTimer;//таймер для обновления
        public System.Timers.Timer RefreshingTimer
        {
            get { return _refreshingTimer; }
            set { _refreshingTimer = value; }
        }

        private Base()
        {
            _gateways = new List<Gateway>();
            _connections = new List<TCPConnection>();
            _refreshingTimer = new System.Timers.Timer(_refreshingInterval);
            _refreshingTimer.Elapsed += new ElapsedEventHandler(_refreshingTimer_Elapsed);
            _refreshingTimer.Enabled = false;
            //....................................

         }

        void _refreshingTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            RefreshConnections();
        }

        public void ConnectToAllPorts()
        {
            foreach (Gateway g in _gateways)
                for (int i = g.MinPort; i <= g.MaxPort; i++)
                {
                    TCPConnection con_ = new TCPConnection(g.IpAddress, i);
                    if (con_.State != ConnectionState.Error)
                        _connections.Add(con_);
                }
            _refreshingTimer.Start();
        }

        public void CloseAllConnections()
        {
            foreach (TCPConnection c in _connections)
            {
                try
                {
                    c.Socked.Disconnect(true);
                }
                catch { }
                c.Socked.Close();
            }
            _connections.Clear();
            _refreshingTimer.Stop();
        }

        public void RefreshConnections()
        {
            foreach (TCPConnection c in _connections)
            {
                Thread t_ = new Thread(c.Refresh);
                t_.Start();
            }
        }
Код: (C#)
    public enum ConnectionState { Error=0, Empty, Online, Offline };
    //устройство на том конце может быть включено\выключено\не подключено\не существует, т.к. порт недоступен
   
    public class TCPConnection
    {
        /// <summary>
        /// Максимальное время ожидания отклика от устройства после отправки и чтения данных
        /// </summary>
        static int _maxResponseTimeout = 5000;
        public static int MaxResponseTimeout
        {
            get { return _maxResponseTimeout; }
            set { _maxResponseTimeout = value; }
        }

        static int _minResponceTimeout = 50;
        public static int MinResponceTimeout
        {
            get { return _minResponceTimeout; }
            set { _minResponceTimeout = value; }
        }

        Socket _socked;
        public Socket Socked
        {
            get { return _socked; }
            set { _socked = value; }
        }

        ConnectionState _state;
        public ConnectionState State
        {
            get { return _state; }
            set { _state = value; }
        }

        IPAddress _gatewayIPAddress;
        public IPAddress GatewayIPAddress
        {
            get { return _gatewayIPAddress; }
            set { _gatewayIPAddress = value; }
        }

        int _portNumber;
        public int PortNumber
        {
            get { return _portNumber; }
            set { _portNumber = value; }
        }

        public TCPConnection(IPAddress ipAddress, int port)
        {
            _socked = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _gatewayIPAddress = ipAddress;
            _portNumber = port;
            _state = ConnectionState.Empty;
            try
            {
                _socked.Connect(ipAddress, port);
                Refresh();
            }
            catch
            {
                _state = ConnectionState.Error;
            }
        }
       
        public void Refresh()
        {
            byte[] message_;
            try
            {
                if (_socked.Connected)
                    message_ = ATSMessages.Instance.GetPocket;
                else
                {
                    //тут создается новый сокет, т.к. попытки оживить старый ни к чему не привели
                    _socked = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    _socked.Connect(_gatewayIPAddress, _portNumber);
                    //впрочем, это тоже не приводит к нужному результату
                    message_ = ATSMessages.Instance.LogOn;
                }
                if (Responds(message_))
                    _state = ConnectionState.Online;
                else
                {
                    if (_socked.Connected)
                        _state = ConnectionState.Offline;
                    else
                        _state = ConnectionState.Empty;
                }
            }
            catch
            {
                _state = ConnectionState.Error;
            }
        }

        bool Responds(byte[] message)
        {
              //тут проверка на то, отвечает ли устройство на посылаемые пакетики
        }
    }

тут вариант без заморочек, в Refresh() используется обычный Connect.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 20-07-2012 14:22 » 

Гайка, у меня и другое правило есть: выкидывать из прототипа всё, что не относится к проблеме. Здесь какой-то пул соединений, которым чёрт знает как пользоваться. И явно вся эта "ботва" с пулом не может иметь отношения к тому, с чего ты начала. Если же отдельно взятое соединение работает, то тогда и проблема в другом.

Цитата: Гайка
тут вариант без заморочек, в Refresh() используется обычный Connect.
И зачем мне код, в котором нет проблем?

Не пойму я тебя.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
гайка
Гость
« Ответ #6 : 20-07-2012 14:50 » 

"без заморочек" не означает "без проблем". тут не используется асинхронное подключение, вот что имелось ввиду.
А начну вырезать куски кода, ты скажешь, что не видишь общей картины.
Смотри. у меня есть устройство (и это именно физическое устройство с физическими портами), открывающее доступ к множеству других устройств через TCP. оно как переводчик. если у него выключено питание, то никакого доступа к портам быть не может.
в том коде в ф-ции Refresh() я пыталась создать новый сокет и подключиться к нему, в том случае, если соединение было по какой-то причине прервано. заново оно не устанавливается. вылетает ошибка.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 20-07-2012 15:01 » 

Гайка, просто неприятно, когда человек не может словами рассказать, что же он делает.

Цитата: Гайка
Смотри. у меня есть устройство (и это именно физическое устройство с физическими портами), открывающее доступ к множеству других устройств через TCP. оно как переводчик. если у него выключено питание, то никакого доступа к портам быть не может.
Хорошо. Это понятно.

Цитата: Гайка
в том коде в ф-ции Refresh() я пыталась создать новый сокет и подключиться к нему, в том случае, если соединение было по какой-то причине прервано. заново оно не устанавливается. вылетает ошибка.
По-твоему в твоём коде написано то, что ты говоришь?

Ну вот код, который синхронно и асинхронно пробует подключиться к недоступному адресу.
Код: (C#)
using System;
using System.Net;
using System.Net.Sockets;

namespace testtcp
{
        class MainClass
        {
                private const int Timeout = 1000;
               
                private static IPEndPoint Point = new IPEndPoint(new IPAddress(new byte[] {1, 2, 3, 4}), 80);
               
                private static void TestSync()
                {
                        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        socket.ReceiveTimeout = Timeout;
                        socket.SendTimeout = Timeout;
                        Console.WriteLine("A socket is created.");
                        try
                        {
                                socket.Connect(Point);
                                Console.WriteLine("A socket is connected.");
                        }
                        catch(Exception exception)
                        {
                                Console.WriteLine("Exception: " + exception.Message);
                        }                      
                        socket.Close();
                        Console.WriteLine("A socket is closed.");
                }
               
                private static void TestAsync()
                {
                        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                        socket.ReceiveTimeout = Timeout;
                        socket.SendTimeout = Timeout;
                        Console.WriteLine("A socket is created.");
                        try
                        {
                                socket.BeginConnect(Point, new AsyncCallback(Callback), socket);
                                Console.WriteLine("A socket is been connecting.");
                        }
                        catch(Exception exception)
                        {
                                Console.WriteLine("Exception: " + exception.Message);
                        }                      
                }
               
                private static void Callback(IAsyncResult result)
                {
                        Socket socket = result.AsyncState as Socket;
                        try
                        {
                                socket.EndConnect(result);
                                Console.WriteLine("A socket is connected.");
                        }
                        catch(Exception exception)
                        {
                                Console.WriteLine("Exception: " + exception.Message);
                        }
                        socket.Close();
                        Console.WriteLine("A socket is closed.");
                }
               
                public static void Main (string[] args)
                {
                        TestSync();
                        TestAsync();
                        Console.WriteLine("Press any key for exit.");
                        Console.ReadKey();
                }
        }
}
В обоих случаях результат абсолютно одинаковый.

P.S. У тебя я не вижу ни вызова Close, как в приличных домах, ни тем более обработки многочисленных исключительных ситуаций, подробно описанных в MSDN.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
гайка
Гость
« Ответ #8 : 20-07-2012 15:04 » 

Дима, слушай, ну почему ты не можешь ответить, не вылив на меня предварительно бочку дерьма?
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #9 : 20-07-2012 15:47 » 

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

Тема сродни в "Срочно пАмАгите", только на более высоком уровне - на следующей ступеньке профлесницы. Там приходит халявщик, пишет задание и чужой код, говорит при этом, что ничего не знает, не понимает, решайте, мол. Ты, конечно, знаешь кое-что, ты пишешь свой код. Но проблема та же самая на другом уровне - на уровне инженерии, архитектуры. Т.е. мне нужно либо спроектировать тебе этот пул потоков с учётом обработки исключительных ситуаций и многопоточности (затратить на это полдня-день), либо молчать в тряпочку. Твоя проблема кодированием или волшебным оператором не решается. Ты этого, похоже, не понимаешь, а мне эта ситуация неприятна.

Разговор будет конструктивным, если ты отложишь свою основную задачу, создашь консольный прототип и начнёшь шаг за шагом, строчка за строчкой оформлять решение, внимательно читая MSDN и тестируя промежуточные результаты. Это будет инженерия, процесс проектирования.

Понятно объяснил?
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines