С Новым годом! Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.87/67: Рейтинг темы: голосов - 67, средняя оценка - 4.87
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86

Событие другого потока (написание клиента на сокетах)

07.12.2011, 13:54. Показов 13699. Ответов 23
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день. Мне нужно разобраться с сокетами, точнее - написать клиента на сокетах. Я использую синхронный TCP сокет. В своем приложении я создаю экземпляр класса Client и вызываю метод Start(), который настраивает сокет и запускает Raid() в новом потоке. Raid() - это метод прослушивания порта.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 public class Client
    {
        private Socket Sock;
 
        private Thread _acceptThread;
 
        public void Start()
        {
            Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Sock.Connect(ClientHelper.GetRemotePoint());
            _acceptThread = new Thread(Read);
            _acceptThread.IsBackground = true;
            _acceptThread.Start();
        }
        public delegate void DelegateReceiveMessage(string package);
        public event DelegateReceiveMessage EventReceiveMessage;
 
        private void Read()
        {
            byte[] buffer = new byte[255];
            try
            {
                while (true)
                {
                    int bytesRead = Sock.Receive(buffer);
                    if (bytesRead > 0)
                         {
                          Debug.WriteLine(ClientHelper.BytesToString(buffer));
                        EventReceiveMessage(ClientHelper.BytesToString(buffer));
                           }
                    else if (bytesRead == 0) return;
                }
            }
            catch (SocketException exc)
            {
                Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Exception: " + exc);
            }
            finally
            {
                Sock.Close();
            }
        }
}
Данные я получаю (Debug то показывает). В чем неудача: я подписываюсь на событие EventReceiveMessage в форме:
C#
1
2
3
4
5
6
7
8
9
        private void Form1_Load(object sender, EventArgs e)
        {
            client.EventReceiveMessage+=new PandaClient.DekegateReceiveMessage(asd);
        }
 
        public void asd(string p)
        {
            richTextBox1.AppendText(p);
        }
То получаю: Exception: System.InvalidOperationException: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'richTextBox1' не из того потока, в котором он был создан.

Я знаю про:
C#
1
2
3
4
5
6
7
8
9
 private void on(string p)
        {
            if (this.InvokeRequired)
                BeginInvoke(new stt(on), new object[] { p });
            else
            {
                richTextBox1.AppendText(p);
            }
        }
Но я не хочу это использовать. Я хочу подписаться на событие другого потока (того, где выполняется Read()) и обрабатывать его как будто событие произошло в главном потоке.
Т.е. чтобы второй листинг работал. Подскажите пожалуйста, куда смотреть?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.12.2011, 13:54
Ответы с готовыми решениями:

По нажатию на кнопку из другого потока, нужно чтобы 2 потока останавливались
Есть 2 потока, в которых в цикле выполняется метод Thread.sleep(200); По нажатию на кнопку из другого потока, нужно чтобы эти 2 потока...

Как из одного потока узнать состояние другого потока
Подскажите пожалуйста, как из одного потока узнать, что другой поток еще не запущен. Например, второй поток формируется в классе...

Вызывть метод одного потока из другого потока
Здравствуйте, подскажите пожалуйста, как можно реализовать такую штуку : есть один поток(1), который вызывает метод у обьекта, этот...

23
 Аватар для Sanprof
96 / 96 / 16
Регистрация: 28.01.2008
Сообщений: 426
07.12.2011, 14:34
а если чуть-чуть поправить
C#
1
2
3
4
5
6
7
private void on(string p)
        {
            if (this.InvokeRequired)
                BeginInvoke((Action)delegate{richTextBox1.AppendText(p);});
            else
                richTextBox1.AppendText(p);
        }
0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
07.12.2011, 14:40  [ТС]
Цитата Сообщение от Sanprof Посмотреть сообщение
а если чуть-чуть поправить
C#
1
2
3
4
5
6
7
private void on(string p)
        {
            if (this.InvokeRequired)
                BeginInvoke((Action)delegate{richTextBox1.AppendText(p);});
            else
                richTextBox1.AppendText(p);
        }
Нет, Вы меня не поняли. Я знаю что так можно делать. Но дело в том, что мой класс Client будут использовать сторонние разработчики, и хочу предоставить им только один метод SendMessage для отправки сообщения. И одно событие - подписался на него, оно произошло - данные на сокет пришли, ты просто берешь их и пользуешься. Не хочется усложнять им жизнь. хочется что бы выглядело как раз как:
C#
1
2
3
4
private void on(string p)
        {
                 richTextBox1.AppendText(p);
        }
0
 Аватар для Sanprof
96 / 96 / 16
Регистрация: 28.01.2008
Сообщений: 426
07.12.2011, 15:37
antsa, ну если вы читали внимательно справку, то обращение к визуальным компонентам из потоков, отличных от главного, запрещается, и с этим мы ничего не можем сделать.
0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
07.12.2011, 17:27  [ТС]
Цитата Сообщение от Sanprof Посмотреть сообщение
antsa, ну если вы читали внимательно справку, то обращение к визуальным компонентам из потоков, отличных от главного, запрещается, и с этим мы ничего не можем сделать.
Я внимательно читал справку, и понимаю что задача сначала перадать данные из потока где выполняется метод Raid, в главный поток, и уже в нем инициализировать событие.
Вопрос в том как передать данные из одного потока в другой?
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
07.12.2011, 18:17
Я тоже задавался этим вопросом. И мне тоже интересно, как же сделать, чтобы событие отрабатывало в основном потоке, даже если оно инициировано в другом. Я так понимаю, что к примеру создали мы класс Client в основном потоке программы, а метод уже работает в другом потоке и оттуда инициирует событие и кажись я нашёл что-то по этой теме, но как использовать пока не разобрался. Я как понял этот интерфейс как раз помогает иницировать событие в том потоке, в котором создан объект (ну мы же предполагаем, что Client создан в основном потоке).

ISynchronizeInvoke

Не по теме:

И не понимаю, зачем у каждого события в начале писать Event? Ведь спутать нереально нисчем и без этого префикса в названии. Не говорю, что у вас также, но вспомнился случай, когда один человек именовал переменные: int iIntegerA; int iIntegerB, double dDoubleSomeVariable; и т.д. Кстати на этом форуме :).

0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
07.12.2011, 18:37  [ТС]
Цитата Сообщение от Casper-SC Посмотреть сообщение
Я тоже задавался этим вопросом. И мне тоже интересно, как же сделать, чтобы событие отрабатывало в основном потоке, даже если оно инициировано в другом. Я так понимаю, что к примеру создали мы класс Client в основном потоке программы, а метод уже работает в другом потоке и оттуда инициирует событие и кажись я нашёл что-то по этой теме, но как использовать пока не разобрался. Я как понял этот интерфейс как раз помогает иницировать событие в том потоке, в котором создан объект (ну мы же предполагаем, что Client создан в основном потоке).

ISynchronizeInvoke

Не по теме:

И не понимаю, зачем у каждого события в начале писать Event? Ведь спутать нереально нисчем и без этого префикса в названии. Не говорю, что у вас также, но вспомнился случай, когда один человек именовал переменные: int iIntegerA; int iIntegerB, double dDoubleSomeVariable; и т.д. Кстати на этом форуме :).

Да, Именно! Изучаю ссылку.

Не по теме:

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

0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
07.12.2011, 18:46
Вот посмотри внимательно на то, как тут инициируется событие да и вообще на остальные изменения, я думаю это более правильно, хотя если и я где-то что-то не верно сделал, то пишите, если дельный совет будет, то прислушаюсь (я к тому, что я сам хочу делать правильно, а не типа я такой супер профи, что может быть сам "Я" \m/ прислушаюсь ).
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    public class Client
    {
        Socket _sock;
        Thread _acceptThread;
 
        public void Start()
        {
            _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _sock.Connect(ClientHelper.GetRemotePoint());
            _acceptThread = new Thread(Read);
            _acceptThread.IsBackground = true;
            _acceptThread.Start();
        }
 
        public delegate void ReceiveMessageHandler(object sender, string package);
        /// <summary>Полученное сообщение (или что там подразумевало реально). Суть в том, что XML комментарии это тема!</summary>
        public event ReceiveMessageHandler ReceiveMessage;
 
        void OnReceiveMessage(string text) //так надо инициировать события
        {
            if (ReceiveMessage != null)
                ReceiveMessage(this, text);
        }
 
        private void Read()
        {
            byte[] buffer = new byte[255];
            try
            {
                while (true)
                {
                    int bytesRead = _sock.Receive(buffer);
                    if (bytesRead > 0)
                    {
                        //кстати, я бы 1 раз вызывал этот метод и передавал в оба метода 1 раз полученные данные
                        Debug.WriteLine(ClientHelper.BytesToString(buffer)); 
                        //Инициируем событие
                        OnReceiveMessage(ClientHelper.BytesToString(buffer));
                    }
                    else if (bytesRead == 0) return;
                }
            }
            catch (SocketException exc)
            {
                Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Exception: " + exc);
            }
            finally
            {
                _sock.Close();
            }
        }
    }
Добавлено через 2 минуты

Не по теме:

Цитата Сообщение от antsa Посмотреть сообщение
У microsoft еще есть рекомендации как называть делегаты и переменные.
Дай ссылку будь другом.



Добавлено через 6 минут
Цитата Сообщение от antsa Посмотреть сообщение
Да, Именно! Изучаю ссылку.
Если разберёшься, что и как делается, выложи тут инфу. Тоже охота разобраться, но сейчас занят другим делом по программированию.
0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
08.12.2011, 05:29  [ТС]
Цитата Сообщение от Casper-SC Посмотреть сообщение
Не по теме:
Сообщение от antsa
У microsoft еще есть рекомендации как называть делегаты и переменные.
Дай ссылку будь другом
Их много, я находил, вот одна из http://msdn.microsoft.com/ru-r... 29012.aspx
Там слева есть "Правила именования":
Соглашения о написании прописными буквами
Общие соглашения об именовании
Имена сборок и библиотек DLL
Имена пространств имен.
Имена классов, структур и интерфейсов
Имена членов типа
Имена параметров
Имена ресурсов
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
08.12.2011, 05:58
Ну вот оттуда же: В именах обработчиков событий (делегатов, используемых как типы событий) используйте суффикс "EventHandler".
Я и назвал в своём примере (правда без Event):
C#
1
public delegate void ReceiveMessageHandler(object sender, string package);
Добавлено через 3 минуты
Хотя походу вполне нормально будет написать: ReceiveMessageEventHandler.

Можно вообще делегат не объявлять, а так написать:
C#
1
public event EventHandler<string> ReceiveMessageEventHandler;
Вместо:
C#
1
public event ReceiveMessageHandler ReceiveMessage;
Добавлено через 3 минуты
Кстати, ссылку передавать на инициирующий событие объект, тоже из рекомендаций. Как раз EventHandler<string> передаёт параметр object sender и string

Добавлено через 8 минут
Короче можно переписать в такой вариант. Но не уверен есть ли острая необходимость оборачивать аргумент в класс, хотя по рекомендациям так надо делать:
В сигнатурах обработчиков событий используйте два параметра с именами "sender" и "e".
Параметр sender должен иметь тип Object, а параметр e должен быть экземпляром или производным классом класса EventArgs.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    public class Client
    {
        Socket _sock;
        Thread _acceptThread;
 
        public void Start()
        {
            _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _sock.Connect(ClientHelper.GetRemotePoint());
            _acceptThread = new Thread(Read);
            _acceptThread.IsBackground = true;
            _acceptThread.Start();
        }
 
        /// <summary>Полученное сообщение (или что там подразумевало реально). Суть в том, что XML комментарии это тема!</summary>
        public event EventHandler<ReceiveMessageEventArgs> ReceiveMessage;
 
        void OnReceiveMessage(string text) //так надо инициировать события
        {
            if (ReceiveMessage != null)
                ReceiveMessage(this, new ReceiveMessageEventArgs(text));
        }
 
        private void Read()
        {
            byte[] buffer = new byte[255];
            try
            {
                while (true)
                {
                    int bytesRead = _sock.Receive(buffer);
                    if (bytesRead > 0)
                    {
                        string text = ClientHelper.BytesToString(buffer);
                        Debug.WriteLine(text);
                        //Инициируем событие
                        OnReceiveMessage(text);
                    }
                    else if (bytesRead == 0) return;
                }
            }
            catch (SocketException exc)
            {
                Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Exception: " + exc);
            }
            finally
            {
                _sock.Close();
            }
        }
    }
 
    /// <summary>Аргументы события бла-бла-бла</summary>
    public class ReceiveMessageEventArgs : EventArgs
    {
        string text;
 
        public ReceiveMessageEventArgs(string text)
        {
            this.text = text;
        }
 
        /// <summary>Сообщение</summary>
        public string Text { get { return text; } }
    }
0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
08.12.2011, 06:08  [ТС]
Меня больше волнует почему не работает. И как вызвать событие из другого потока. Я уже 3 день сижу...
0
 Аватар для агерон
447 / 300 / 65
Регистрация: 12.10.2009
Сообщений: 1,162
08.12.2011, 06:22
твоя проблема не в событии а в том что ты обращаешься к визуальным элементам из фонового потока
вот решение
C#
1
2
3
4
5
6
7
8
9
10
11
        Action<Label, string> actionLabel = delegate(Label label, string text)
        { label.Text = text; };
 
        private void TestInvoke()
        {
            ThreadPool.QueueUserWorkItem(delegate(object sender)
            {
                Label label = (Label)sender;
                label.Invoke(actionLabel, new object[] { label, "10000" });
            }, label1);
        }
label1 - метка на форме, ThreadPool обьект управления фоновыми потоками
label.Invoke - выпонение делегата в контексте главного потока
0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
08.12.2011, 06:30  [ТС]
Да, это мы знаем. В том то и соль. И хочу передать событие в другой поток. Чтобы потом просто на него подписываться. Сейчас делаю Invoke для своего класса.
0
 Аватар для агерон
447 / 300 / 65
Регистрация: 12.10.2009
Сообщений: 1,162
08.12.2011, 06:50
зачем писать Invoke для класса???
тебе же русским языком сказано
"Exception: System.InvalidOperationException: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'richTextBox1' не из того потока, в котором он был создан"
т. е. твоя проблема не в том что ты подписался на событие из фонового потока А В ТОМ ЧТО К ВИЗУАЛЬНЫМ ЭЛЕМЕНТАМ МОЖНО ОБРАЩАТЬСЯ ТОЛЬКО ИЗ ОСНОВНОГО ПОТОКА, и передача события (интересно кстати как ты это организуешь :-) ) не играет в этом роли!!!
Выход из ситуации таков... если есть фоновый поток который работает с визуальными элементами то обновлять данные визуального элемента нужно ТОЛЬКО через метод Invoke текущего визуального элемента передавая методу Invoke делегат и параметры делегата для обновления

P. S. кстати подписываться можно на любое событие любого класса из любого потока, правда не факт что не будет проблем с синхронизацией
0
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
08.12.2011, 09:43  [ТС]
Цитата Сообщение от агерон Посмотреть сообщение
зачем писать Invoke для класса???
тебе же русским языком сказано
"Exception: System.InvalidOperationException: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления 'richTextBox1' не из того потока, в котором он был создан"
т. е. твоя проблема не в том что ты подписался на событие из фонового потока А В ТОМ ЧТО К ВИЗУАЛЬНЫМ ЭЛЕМЕНТАМ МОЖНО ОБРАЩАТЬСЯ ТОЛЬКО ИЗ ОСНОВНОГО ПОТОКА, и передача события (интересно кстати как ты это организуешь :-) ) не играет в этом роли!!!
Выход из ситуации таков... если есть фоновый поток который работает с визуальными элементами то обновлять данные визуального элемента нужно ТОЛЬКО через метод Invoke текущего визуального элемента передавая методу Invoke делегат и параметры делегата для обновления

P. S. кстати подписываться можно на любое событие любого класса из любого потока, правда не факт что не будет проблем с синхронизацией
Мой третий пост:
Нет, Вы меня не поняли. Я знаю что так можно делать. Но дело в том, что мой класс Client будут использовать сторонние разработчики, и хочу предоставить им только один метод SendMessage для отправки сообщения. И одно событие - подписался на него, оно произошло - данные на сокет пришли, ты просто берешь их и пользуешься. Не хочется усложнять им жизнь. хочется что бы выглядело как раз так.

Добавлено через 2 часа 47 минут
Задача РЕШЕНА!!! С помощью BackgroundWorker.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class Client
    {
        private Socket Sock;
 
        public BackgroundWorker bgrw = new BackgroundWorker();
 
        public void Start()
        {
            Sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            Sock.Connect(ClientHelper.GetRemotePoint());
            bgrw.WorkerReportsProgress = true;
 
            bgrw.DoWork+=new System.ComponentModel.DoWorkEventHandler(Read);
            bgrw.ProgressChanged += new ProgressChangedEventHandler(dsa);
            bgrw.RunWorkerAsync();
        }
 
        public void Stop()
        {
            Sock.Shutdown(SocketShutdown.Both);
            Sock.Close();
        }
 
        public void SendMessage(Package Message)
        {
            Sock.Send(ClientHelper.StringToBytes(Message));
        }
 
        private void Read(object sender, DoWorkEventArgs e)
        {
            byte[] buffer = new byte[255];
            try
            {
                while (true)
                {
                    int bytesRead = Sock.Receive(buffer);
                    if (bytesRead > 0)
                    {
                        string pak = ClientHelper.BytesToString(buffer);
                        bgrw.ReportProgress(0, new String { pak });
                    }
                    else if (bytesRead == 0) return;
                }
            }
            catch (SocketException exc)
            {
                Console.WriteLine("Socket exception: " + exc.SocketErrorCode);
            }
            catch (Exception exc)
            {
                Console.WriteLine("Exception: " + exc);
            }
            finally
            {
                Sock.Close();
            }
        }
 
        private void dsa(object sender, ProgressChangedEventArgs e)
        {
            string pa2 = e.UserState as string;
            MyEve(pa2);         
        }
 
        public delegate void MyDel(string str);
        public event MyDel MyEve;
    }
тогда в форме можно просто написать:
C#
1
2
3
4
5
6
7
8
9
        private void Form1_Load(object sender, EventArgs e)
        {
            client.MyEve+=new PandaClient.MyDel(on);
        }
 
        public void on(string s)
        {
            richTextBox1.AppendText(s + "\n");
        }
То что и требовалось!!!!

Частично использованы материалы: backgroundWorker и формы...

И да!
Цитата Сообщение от sMario Посмотреть сообщение
В общем и целом - всё-равно колхоз получается Но работает, - и то хорошо.

Очень ждём 5 шарп. Ибо текущая реализация работы с потоками выглядит удручающе.
Сказать что я согласен, это ничего не сказать...
0
 Аватар для агерон
447 / 300 / 65
Регистрация: 12.10.2009
Сообщений: 1,162
08.12.2011, 14:21
мда.... месье знает толк в извращениях, мой тебе совет почитай про синхронизацию и пул потоков, асинхронные события тогда может поймешь что для твоей супер - пупер задачи с головой хватит C# 2.0, код решения не стал делать ибо ты все равно не поймешь как он работает
0
215 / 215 / 20
Регистрация: 18.05.2010
Сообщений: 865
08.12.2011, 14:38
Цитата Сообщение от antsa Посмотреть сообщение
Вопрос в том как передать данные из одного потока в другой?
Цитата Сообщение от Casper-SC Посмотреть сообщение
Я тоже задавался этим вопросом. И мне тоже интересно, как же сделать, чтобы событие отрабатывало в основном потоке, даже если оно инициировано в другом
что то я вообще не пойму суть проблемы и вообще зачем инициоровать и выполнять событие в другом потоке???
1. что значит передать данные с одного потока в другой? у потока есть данные? может данные с одного экземпляра класса в другой? тут вообще нету проблем, присваивай прямо и все. (за исключением визуальных объектов)
2. а зачем выполнять именно в том потоке? если конечно это не визуальный элемент. можно просто синхронизировать доступ. Я не вижу причин зачем заморачиваться и выполнять все в одном потоке !!!

я внимательно читаю тему но что то не доходит до меня зачем такие заморочки.
0
Эксперт .NET
 Аватар для Casper-SC
4434 / 2094 / 404
Регистрация: 27.03.2010
Сообщений: 5,657
Записей в блоге: 1
08.12.2011, 20:56
Цитата Сообщение от Башир Посмотреть сообщение
тут вообще нету проблем, присваивай прямо и все. (за исключением визуальных объектов)
Ну речь как раз об обработчиках событий взаимодействующих с интерфейсом. BackgroundWorker в обработчике события ProgressChanged например не требует вызова Invoke для обращения к элементам окна. Основное выполнение работы идёт в другом потоке, а обработчик я как понимаю уже выполняется в основном, вот тоже самое и хотелось бы сделать в своём классе. Что тут не понятного? Вот и есть пример требуемого поведения.

Цитата Сообщение от Башир Посмотреть сообщение
Я не вижу причин зачем заморачиваться и выполнять все в одном потоке !!!
Ненадо ничего выполнять в одном потоке. Выполнил работу в другом потоке, инициировал событие так, чтобы уже его обработчик работал в основном потоке. Как я уже говорил так умеет делать BackgroundWorker. Теперь понятно?

Цитата Сообщение от antsa Посмотреть сообщение
Но дело в том, что мой класс Client будут использовать сторонние разработчики, и хочу предоставить им только один метод SendMessage для отправки сообщения.
Я смотрю не очень то беспокоишься о сторонних разработчиках судя по последнему варианту кода. Во первых событие инициируется коряво, если не подписаться на него, то будет эксепшен. Заметил, даёшь дельные советы и в большинстве случаев их игнорируют (видимо своё роднее). Советую посмотреть код внимательно в сообщении.

C#
1
2
string pak = ClientHelper.BytesToString(buffer);
bgrw.ReportProgress(0, new String { pak });
Это вообще не компилится. И не имеет смысла, просто pak не передаётся? Надо создавать ещё строку перед передачей (судя по всему это требовалось)?

Цитата Сообщение от агерон Посмотреть сообщение
и передача события (интересно кстати как ты это организуешь :-) ) не играет в этом роли!!!
А как в BackgroundWorker организовали? Ещё раз скажу, там не нужно ничего вызывать, просто обращаешься к элементам окна и всё.

Цитата Сообщение от агерон Посмотреть сообщение
мда.... месье знает толк в извращениях
Ага. Мне кажется всё же надо искать правильное решение, а не через воркер делать. Заодно можно чему-то научиться новому.
1
 Аватар для агерон
447 / 300 / 65
Регистрация: 12.10.2009
Сообщений: 1,162
09.12.2011, 04:09
эххх не хотелось особо заморачиватся но раз пошла такая пляска держите
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
 
namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            Close();
        }
 
        TcpListener tcpListener = new TcpListener(10000);
 
        public class AsyncServerData
        {
            public Socket SoсketServer { get; set; }
            public byte[] Data { get; set; }
 
            public AsyncServerData(Socket socketServer, byte[] data)
            {
                SoсketServer = socketServer;
                Data = data;
            }
        }
 
        public class AsyncClientData
        {
            public Socket SocketClient {get;set;}
            public ListBox ListBox { get; set; }
 
            public AsyncClientData(Socket socketClient, ListBox listBox)
            {
                SocketClient=socketClient;
                ListBox = listBox;
            }
        }
 
        static Action<ListBox, string> updateListBox = delegate(ListBox listBox, string data)
        {
            listBox.Items.Add(data);
        };
 
        static AsyncCallback asyncCallBackAcceptServer = delegate(IAsyncResult asyncResult)
        {
            AsyncServerData asyncServerData = (AsyncServerData)asyncResult.AsyncState;
            Socket client=asyncServerData.SoсketServer.EndAccept(asyncResult);
            client.Send(asyncServerData.Data);
            client.Disconnect(false);
            asyncServerData.SoсketServer.BeginAccept(asyncCallBackAcceptServer, asyncServerData);
        };
 
        static AsyncCallback asyncCallBackConnectClient = delegate(IAsyncResult asyncResult)
        {
            AsyncClientData asyncClientData = (AsyncClientData)asyncResult.AsyncState;
            asyncClientData.SocketClient.EndConnect(asyncResult);
            byte[] data = new byte[11];
            asyncClientData.SocketClient.Receive(data);
            string result = Encoding.Default.GetString(data);
            asyncClientData.SocketClient.Disconnect(false);
            asyncClientData.ListBox.Invoke(updateListBox, new object[] { asyncClientData.ListBox, result });
            Connect(asyncClientData.ListBox);
        };
 
        private void button1_Click(object sender, EventArgs e)
        {
            tcpListener.Start(1000);
            byte[] data = Encoding.Default.GetBytes(textBox1.Text);
            tcpListener.Server.BeginAccept(asyncCallBackAcceptServer,
                new AsyncServerData(tcpListener.Server, data));
        }
 
        private static void Connect(ListBox listBox)
        {
            TcpClient tcpClient = new TcpClient();
            tcpClient.BeginConnect("192.168.1.2", 10000, asyncCallBackConnectClient, new AsyncClientData(tcpClient.Client, listBox));
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            Connect(listBox1);
        }
    }
}
в приложении полный проект
Вложения
Тип файла: rar WindowsFormsApplication4.rar (9.7 Кб, 70 просмотров)
3
 Аватар для antsa
19 / 19 / 4
Регистрация: 04.07.2010
Сообщений: 86
09.12.2011, 05:23  [ТС]
Цитата Сообщение от Casper-SC Посмотреть сообщение
Сообщение от Башир
тут вообще нету проблем, присваивай прямо и все. (за исключением визуальных объектов)
Ну речь как раз об обработчиках событий взаимодействующих с интерфейсом. BackgroundWorker в обработчике события ProgressChanged например не требует вызова Invoke для обращения к элементам окна. Основное выполнение работы идёт в другом потоке, а обработчик я как понимаю уже выполняется в основном, вот тоже самое и хотелось бы сделать в своём классе. Что тут не понятного? Вот и есть пример требуемого поведения.
Сообщение от Башир
Я не вижу причин зачем заморачиваться и выполнять все в одном потоке !!!
Ненадо ничего выполнять в одном потоке. Выполнил работу в другом потоке, инициировал событие так, чтобы уже его обработчик работал в основном потоке. Как я уже говорил так умеет делать BackgroundWorker. Теперь понятно?
Да, Casper-SC все верно говорит.
Цитата Сообщение от Casper-SC Посмотреть сообщение
Я смотрю не очень то беспокоишься о сторонних разработчиках судя по последнему варианту кода. Во первых событие инициируется коряво, если не подписаться на него, то будет эксепшен. Заметил, даёшь дельные советы и в большинстве случаев их игнорируют (видимо своё роднее). Советую посмотреть код внимательно в сообщении.
Нет, в оригинальном коде я все поменял как говорили выше, согласно правилам, а здесь, чтобы исходник был похож на тот, что я постил в начале решил оставить с тем же почерком как и был. А так ты прав, я перечитал эти правила и теперь буду им следовать.
Цитата Сообщение от Casper-SC Посмотреть сообщение
Ага. Мне кажется всё же надо искать правильное решение, а не через воркер делать. Заодно можно чему-то научиться новому.
Блин, мужики, кончено я согласен что это не айс, но есть такая штука как время, и оно не ждет, я сейчас не могу с этим неделями возиться, ближе к концу если время останется эта часть перепишется я надеюсь. Возможно сделаю асинхронно как предлагал агерон.
Спасибо!
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
09.12.2011, 05:23
Помогаю со студенческими работами здесь

Управление объектами потока из другого потока
Доброго времени. Есть два потока, один GUI, второй рабочий - делает снапшоты открытых окон, сравнивает их, передаёт потоку GUI...

Написание прокси сервера на сокетах. Проброс сообщений основному серверу и возврат значений через прокси
Есть 3 приложения. 1. Клиент. 2. Прокси сервер. 3. Сервер. Что задумано: Запускается клиент и получает параметры конфигурации с...

Написание клиента
У меня следующаяя проблема. Нужен клиент для закачки фото на сервер. Я никогда не кодил для веба и изучать буду по написанию клиента. Я...

Написание бота на сокетах: быть или не быть?
Хай всем!!! =) Читаю литературу по сокетах, хочу научится бот на сокетах написать к приложениям ВК. Что посоветуете?

Написание IRC клиента
Господа, в общем мне необходимо написать простейший клиент IRC на андроид. Эклипс, андроид сдк, все дела давно стоят, но врубиться в тему...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ * Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её. Последовательность действий:. . .
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение. И на уровне агентов добавится между грибами или бактериями взаимодействий. До того я пробовал подход через многомерные массивы,. . .
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост. Налог на собак: https:/ / **********/ gallery/ V06K53e Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf Пост отсюда. . .
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop? Ниже её машинный перевод. После долгих разбирательств я наконец-то вернула себе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru