Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.57/7: Рейтинг темы: голосов - 7, средняя оценка - 4.57
videoLoL
7 / 7 / 2
Регистрация: 20.04.2011
Сообщений: 163
1

Клиент-Серверное приложение: как отсоединиться от сервера

05.09.2012, 16:43. Просмотров 1403. Ответов 6
Метки нет (Все метки)

Клиент на C#
Сервер на ANSI-C

Сервер подаёт структуры размером в 38байт.
Клиент Получает Байты и чз BitConverter я получаю свои данные(пробовал чз Маршал оказалось слишком долго, пробовал чз Unsafe-код с применением fixed оказалось не важно почему-то встаёт поток колом будто буфер переполняется где то и данные застывают)
я вывожу данные в Textbox.чз Бесконечный цикл.Данные выводятся всё нормально.
Но вопрос делетанский как отсоединится от сервера?
У меня есть кнопка-Коннект, нажимаю данные пошли.но после нажатия форма не активна.хочу сделать что бы при повторном нажатие происходил дисконнект. Что мне нужно для этого сделать
Код Клиента.


Добавлено через 57 минут
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
public void Connect(String server, Int32 port)
        {
            byte[] buf12 = new byte[8048];
            TcpClient client = null;
            NetworkStream networkStream = null;
            //client.NoDelay = false;
            client = new TcpClient(server, port);
            networkStream = client.GetStream();
            int k = 0;
            while(true)
            try
            {
                button1.Enabled = true;
                buf12 = new byte[8048];
                //Подключение к серверу
 
                int read = networkStream.Read(buf12, 0, buf12.Length);
                k++;
                for (int i = 40; i <= read; i = i + 40)
                {
                    textBox1.AppendText("\n" + BitConverter.ToInt16(buf12, i - 8).ToString() + "\n");
                    table.Rows[0].Cells[1].Value = BitConverter.ToSingle(buf12, i - 40);
                    table.Rows[1].Cells[1].Value = BitConverter.ToSingle(buf12, i - 36);
                    table.Rows[2].Cells[1].Value = BitConverter.ToSingle(buf12, i - 32);
                    table.Rows[3].Cells[1].Value = BitConverter.ToSingle(buf12, i - 28);
                    table.Rows[4].Cells[1].Value = BitConverter.ToSingle(buf12, i - 24);
                    table.Rows[5].Cells[1].Value = BitConverter.ToSingle(buf12, i - 20);
                    table.Rows[6].Cells[1].Value = BitConverter.ToInt16(buf12, i - 16);
                    table.Rows[7].Cells[1].Value = BitConverter.ToSingle(buf12, i - 12);
                    table.Rows[8].Cells[1].Value = BitConverter.ToInt16(buf12, i - 8);
                    table.Rows[9].Cells[1].Value = BitConverter.ToInt16(buf12, i - 6);
                    table.Rows[10].Cells[1].Value = BitConverter.ToInt16(buf12, i - 4);
                }
                textBox1.AppendText("\n");
               // client.Close();
            }
            // ошибка соединения
            catch (Exception e)
            {
                MessageBox.Show(e.Message.ToString());
                client.Close();
            }
        }
Добавлено через 15 минут
Отвечу на свой вопрос
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
private void button1_Click(object sender, EventArgs e)
        {
            Thread _t = new Thread(new ThreadStart(Connect));
            _t.IsBackground = true;
            _t.Start();
            
        }
       
                private void Connect()
        {
            String server = "192.168.10.100";
            Int32 port = 6000;
            byte[] buf12 = new byte[8048];
            TcpClient client = null;
            NetworkStream networkStream = null;
            //client.NoDelay = false;
            client = new TcpClient(server, port);
            networkStream = client.GetStream();
            int k = 0;
            while(true)
            try
            {
                button1.Enabled = true;
                buf12 = new byte[8048];
                //Подключение к серверу
 
                int read = networkStream.Read(buf12, 0, buf12.Length);
                k++;
                for (int i = 40; i <= read; i = i + 40)
                {
                    //MethodInvoker mi = delegate { textBox1.AppendText("\n" + BitConverter.ToInt16(buf12, i - 8).ToString() + "\n"); };
                    //textBox1.Invoke(mi);
                    //textBox1.AppendText("\n" + BitConverter.ToInt16(buf12, i - 8).ToString() + "\n");
                    table.Rows[0].Cells[1].Value = BitConverter.ToSingle(buf12, i - 40);
                    table.Rows[1].Cells[1].Value = BitConverter.ToSingle(buf12, i - 36);
                    table.Rows[2].Cells[1].Value = BitConverter.ToSingle(buf12, i - 32);
                    table.Rows[3].Cells[1].Value = BitConverter.ToSingle(buf12, i - 28);
                    table.Rows[4].Cells[1].Value = BitConverter.ToSingle(buf12, i - 24);
                    table.Rows[5].Cells[1].Value = BitConverter.ToSingle(buf12, i - 20);
                    table.Rows[6].Cells[1].Value = BitConverter.ToInt16(buf12, i - 16);
                    table.Rows[7].Cells[1].Value = BitConverter.ToSingle(buf12, i - 12);
                    table.Rows[8].Cells[1].Value = BitConverter.ToInt16(buf12, i - 8);
                    table.Rows[9].Cells[1].Value = BitConverter.ToInt16(buf12, i - 6);
                    table.Rows[10].Cells[1].Value = BitConverter.ToInt16(buf12, i - 4);
                }
                //textBox1.AppendText("\n");
               // client.Close();
            }
            // ошибка соединения
            catch (Exception e)
            {
                MessageBox.Show(e.Message.ToString());
                client.Close();
            }
        }// end connection
    }
Добавлено через 52 секунды
Проблема теперь с TextBox'ом Пишет Недопустимая операция в нескольких потоках. =(

Добавлено через 13 минут
C#
1
2
                    Action action = () => textBox1.Text = ("\n" + BitConverter.ToInt16(buf12, i - 8).ToString() + "\n");
                    textBox1.Invoke(action);
Не помогает.
Когда навожу на закрытие формы нажимаю на ЛКМ и удерживаю её то происходит чёрти что(на форме есть DataGridView в ней пишутся значения которые получается Клиент от Сервера.так вот значения начинают "прыгать" построкам и т.д.) но потом нормализуется. Почему так происходит?и как мне это исправить?и как мне сделал вывод в ТекстБокс

Добавлено через 2 часа 44 минуты
Подскажите пожалуйста как правильно "закрыть поток"?
я предполагаю что надо подать на сервер значение "закрыть соединение"?
потом закрыть у себя соединение. и тогда поток сам закроется?а за ним и основной можно закрывать(который Main)?
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.09.2012, 16:43
Ответы с готовыми решениями:

Клиент-серверное приложение: как написать реакцию сервера на каждое сообщение от клиента
В общем пытаюсь разобраться с сетью в C#, условная задача написать сервер - который осуществляет...

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

Клиент-серверное приложение: как определить, что сервер/клиент не отвечает в течении определенного времени
Пишу клиент-серверное приложение. Использую TCPListener и TCPClient. Вопрос: как определить что...

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

Как написать клиент-серверное приложение
Привет всем, хочу написать сервер.Пересмотрел кучу уроков и статей и т.д. ,но там нет подробного...

6
Spectral-Owl
591 / 566 / 157
Регистрация: 29.06.2010
Сообщений: 1,610
Завершенные тесты: 1
05.09.2012, 17:00 2
про текст-бокс скажу, к контролам при многопоточности обращаюсь исключительно так:
C#
1
BeginInvoke(new MethodInvoker(()=>texBox.Text=newRecivedText));
а код на закрытие клиента у меня уморительный:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        public void Stop(Exception e)
        {
            //оповещение о закрытии
            if (OnStop != null) OnStop(this, e);//событие
 
            //сброс флагов
            WantRead = false;
            isConnected = false;
 
            //остановка всего подряд
            try { TimerLister.Stop();       }catch{}//таймер
            try { Sock.Disconnect(false);}catch{}//сокет
            try { Sock.Close();              }catch{}//сокет
            try { ReadThread.Abort();     }catch{}//поток
        }
1
videoLoL
7 / 7 / 2
Регистрация: 20.04.2011
Сообщений: 163
05.09.2012, 17:08  [ТС] 3
Спасибо за текст бокс)).а вот по изящнее как сделать?я просто в потоках не силён=(.знаю лишь основы потоков. Я как понимаю Abort() останавливает поток(грубо говоря делает "паузу")?
Нельзя ли проще у себя сделать client.Close(), а после поток сам закроется? или я не прав? (где TcpClient client)
P.S.: Почему На ТекстБокс ругнулся, а на table.Rows[0].Cells[1].Value = BitConverter.ToSingle(buf12, i - 40); нет?
0
Spectral-Owl
591 / 566 / 157
Регистрация: 29.06.2010
Сообщений: 1,610
Завершенные тесты: 1
05.09.2012, 17:32 4
а черт его знает, может таблица создавалась в том же потоке, где изменяется её значение, а текст-бокс по другому?
а по поводу потоков и клиентов: у тебя в потоке нетворкСтрим постоянно читает байты, в то время как определяется видом "client.GetStream();". при закрытии клиента без завершения потока я думаю у тебя нетворкСтрим выдаст ошибку о отключенности клиента. в обработчике этой ошибки стоит закрытие клиента, что собственно вызывет ещё одну ошибку, т.к. клиент и так закрыт(а может и не вызывет, я с сокетами работал постоянно)). после или выдачи, или обработки данной ошибке нетворкстрим заново попытается считать с клиента сообщение, заново выдаст ошибку и т.д.

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


Abort:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
// Сводка:
        //     Вызывает исключение System.Threading.ThreadAbortException в вызвавшем его
        //     потоке для того, чтобы начать процесс завершения потока. Вызов данного метода
        //     обычно завершает поток.
        //
        // Исключения:
        //   System.Security.SecurityException:
        //     Вызывающий код не имеет необходимого разрешения.
        //
        //   System.Threading.ThreadStateException:
        //     Поток, находящийся в состоянии завершения, приостановлен.


Join:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
//
        // Сводка:
        //     Блокирует вызывающий поток до завершения потока, продолжая отправлять стандартные
        //     сообщения COM и SendMessage.
        //
        // Исключения:
        //   System.Threading.ThreadStateException:
        //     Вызывающий поток произвел попытку присоединить поток, находящийся в состоянии
        //     System.Threading.ThreadState.Unstarted.
        //
        //   System.Threading.ThreadInterruptedException:
        //     Во время ожидания работа потока была прервана.
0
videoLoL
7 / 7 / 2
Регистрация: 20.04.2011
Сообщений: 163
05.09.2012, 17:41  [ТС] 5
1.Спасибо за подробный ответ. Т.е. я делаю что то вроде
while(client.Connected) ?
2.Т.е. При нажатие на Дисконнект(я пишу client.Close() после _thread.Abort() и всё?)
3.Да вы правы у меня НетворкСтрим вываливал кучу МессаджБоксов-_-.
4.Мне надает покоя что данные идут в 1сек - 1000структур.
как мне правильно сделать?подать серверу что пора закрыватся и _thread.Abort() или делать client.Close();_tread.Abort()?
5.С текстБоксом стало понятно..а если мне надо ещё выводить 3 графика от переменных которые я получаю..делать 3 BeginInvoke?
0
Spectral-Owl
591 / 566 / 157
Регистрация: 29.06.2010
Сообщений: 1,610
Завершенные тесты: 1
05.09.2012, 18:03 6
1. да
2. если у клиента нет метода .Disconect(..); то почти. потом кое-какие вызовы методов придётся заключить в try-catch, так как иногда срабатывает двойное отключение, а попытка отключить то что уже отключено часто заканчивается Exception-ом.
5.при обращении к контролам из любого потока кроме базового (а в данном случае получение данных как раз в другом потоке) надо BeginInvoke или эквивалент оному) правда он позволяет записывать и не по одной операции

C#
1
2
3
4
5
6
BeginInvoke(new MethodInvoker(()=>
{
texBox.Text=newRecivedText;
..
..
}));
хотя мог с сигнатурой напутать)
1
videoLoL
7 / 7 / 2
Регистрация: 20.04.2011
Сообщений: 163
06.09.2012, 13:11  [ТС] 7
2.Насколько я помню то в TcpClien нет метода Disconnet есть Close.Но смысл этого не меняет)
Пишут на форумах что Abort или Join это тоже самое что плевать Омоновцу в лицо , в надежде что ничего не будет. Пишут что в Thread _thread = new Thread(new ThreadStart(СтартПроцесс)); В методе SConnect должна быть какая то переменная отвечающая за "конец" (Логичнее указать некую булеву переменную Б1, потом в Вашей функции СтартПроцесс выполнять процесс до тех пор пока Б1 = труе)
Но у меня Данные могут идти бесконечно=(.Не могу понять как правильно закрыть поток=(

Т.е. Сначала надо закрыть соединение.Потом присвоить переменной что соединение закрыто.Потом как то поток сам закроется?Беда читаю про потоки в rsdn но что то понять не могу как мне тут поступить

Добавлено через 14 часов 18 минут
1.когда я делаю чз BeginInvoke значение "идут" в текст боксе, чз пару секунд они все обнуляются далее снова появляются значения и снова обнуляются.
Как это исправить?

2.делал тоже самое но чз Invoke..значения идут..но при дисконнекте поток уходит в WaitSleepJoin а статус его True;
Если пункт 1. не удачно выбран в моём случае тогда как этот пункт исправить?

Добавлено через 3 минуты
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
        private void ThreadTextBox()
        {
            textBoxThread.Clear();
            textBoxThread.AppendText("Поток(и):" + Environment.NewLine +
                "Имя: " + _t.Name + Environment.NewLine +
                "Статус: " + _t.IsAlive.ToString() + Environment.NewLine +
                "Состояние: " + _t.ThreadState.ToString());
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (!flag)
                {
                    button1.Text = "Disconnect";
                    flag = true;
                    _t = new Thread(new ThreadStart(Connect));
                    _t.IsBackground = false;
                    _t.Name = "Thread 1";
                    //_t.SetApartmentState(ApartmentState.STA);
                    _t.Start();
                    ThreadTextBox();
                }
                else
                {
                    button1.Text = "Connect";
                    flag = false;
                    _t.Join(500);
                    ThreadTextBox();
                }
            }
            catch (Exception E)
            {
                MessageBox.Show(E.Message);
            }
        }
 
        private void Connect()
        {
            String server = "192.168.10.100";
            Int32 port = 6000;
            byte[] buf12 = new byte[8048];
            TcpClient client = null;
            NetworkStream networkStream = null;
            client = new TcpClient(server, port);
            networkStream = client.GetStream();
            
            while (flag)
            {
                try
                {
                    button1.Enabled = true;
                    buf12 = new byte[8048];
                    int read = networkStream.Read(buf12, 0, buf12.Length);
                    for (int i = 40; i <= read; i = i + 40)
                    {
                        Invoke(new MethodInvoker(() => textBox1.Text = ("\n" + BitConverter.ToInt16(buf12, i - 8).ToString() + "\n")));
                        table.Rows[0].Cells[1].Value = BitConverter.ToSingle(buf12, i - 40);
                        table.Rows[1].Cells[1].Value = BitConverter.ToSingle(buf12, i - 36);
                        table.Rows[2].Cells[1].Value = BitConverter.ToSingle(buf12, i - 32);
                        table.Rows[3].Cells[1].Value = BitConverter.ToSingle(buf12, i - 28);
                        table.Rows[4].Cells[1].Value = BitConverter.ToSingle(buf12, i - 24);
                        table.Rows[5].Cells[1].Value = BitConverter.ToSingle(buf12, i - 20);
                        table.Rows[6].Cells[1].Value = BitConverter.ToInt16(buf12, i - 16);
                        table.Rows[7].Cells[1].Value = BitConverter.ToSingle(buf12, i - 12);
                        table.Rows[8].Cells[1].Value = BitConverter.ToInt16(buf12, i - 8);
                        table.Rows[9].Cells[1].Value = BitConverter.ToInt16(buf12, i - 6);
                        table.Rows[10].Cells[1].Value = BitConverter.ToInt16(buf12, i - 4);
                      
                    }
                }
                // ошибка соединения
                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                    //Подстраховка отрубать всё. No Good
                    networkStream.Flush();
                    networkStream.Close();
                    client.Close();
                    _t.Interrupt();
                    _t.Abort();
                    _t.Join(500);
                }
            }
            // end connection
            if (!flag)
            {
                networkStream.Flush();
                networkStream.Close();
                client.Close();
                _t.Interrupt();
                _t.Abort();
                _t.Join(500);
                return;
            }
        }
Добавлено через 4 часа 39 минут
Проблема в том что с TextBox'ом работает Invoke
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.textBox1.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.textBox1.Text = text;
            }
        }
а с Chart'ом некорректно.Т.е. Данные идут в Чарт, чз некоторое время данные начинают приходить "левые"..думаю из за того что данные быстро поступают и поток не успевает записывать всё это дело БитКонвертировать + вызвать инвок на ТекстБокс и Чарт одновременно..данные которые приходят по сети, то ли теряются то ли приходят не те=(..разобраться ну никак не могу.
Помогите вызвать 3 разных Chart'a из другого потока
Invoke,BeginInvoke не помогают..думаю уже делать
C#
1
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
Дело в том что данные которые приходят чз TCP нужны как и TextBox'у так и 3-м Chart'ам и нескольким TextBox'ом.
0
06.09.2012, 13:11
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.09.2012, 13:11

Как организовать клиент-серверное приложение
Делаю лабораторную: необходимо написать три приложения на с#, два сервера (ServerInput и...

Как создать простенькое клиент-серверное приложение
вобщем такая задача: создать простенькое клиентское и серверное приложение, чтобы с клиента можно...

Как написать клиент-серверное приложение для управления COM портом
Здравствуйте, Написал в Visual Studio 2010 программу для работы с COM портом - отправка...


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

Или воспользуйтесь поиском по форуму:
7
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.