Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
2 / 2 / 2
Регистрация: 08.11.2014
Сообщений: 35
1

В массив выводить данные-id клиента, данные серверу и данные, отправленные сервером

29.04.2015, 09:19. Просмотров 1387. Ответов 8
Метки нет (Все метки)


Здравствуйте. Имеется клиент-серверное приложение, вопрос по стороне сервера.
Имеется backgroundworker-bw_clientReceining:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
TcpListener serverSocket = new TcpListener(8888);
            TcpClient clietnSocket = default(TcpClient);
 
 
            serverSocket.Start();
            bw_clientReceining.ReportProgress(1);
            while (true | !bw_clientReceining.CancellationPending)
            {
                counterClient++;
                clietnSocket = serverSocket.AcceptTcpClient();
                bw_clientReceining.ReportProgress(2);
                handleClient client = new handleClient();
                client.startClient(clietnSocket, Convert.ToString(counterClient));
                Thread.Sleep(5000);
                DataClientToServerID.Add("");
                DataClientToServerStatus.Add("");
                DataServerTOClientStatus.Add("");
            }
            clietnSocket.Close();
            serverSocket.Stop();
и есть класс handleClient:
Принимаем новых клиентов в классе:
C#
1
2
3
4
5
6
7
public void startClient(TcpClient inClientSocket, string clientNO)
        {
            this.clientSocket = inClientSocket;
            clientNO = clientNO;
            Thread ctThread = new Thread(doChat);
            ctThread.Start();
        }
так же в классе есть функция общения doChat()-её код опустим


Задача заключается вот в чём:
Хочу в массив выводить данные-ид клиента, данные серверу и данные отправленные сервером.
Смотрите, когда я завожу нового клиента, он в функцию startClient(TcpClient inClientSocket, string clientNO)-передаёт clientNO-то есть я думал это использовать в качестве идентификатора строки массива.

Единственное решение, которое пришло в голову, это создать ещё один backgroundworker-bw_statusUp и в нём бесконечный цикл сделать, где мы будем получать свойство нашего класса. В класс handleClient добавил свойства:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int ClientNo
        {
            get
            {
                return clientNO;
            }
        }
        public string ClientID
        {
            get
            {
                return clID;
            }
        }

Но я не учёл того, что в backgroundworker-bw_statusUp нет возможножности дотянуться до класса handleClient, так как он в другом backgroundworker потоке создан.
Вопросы:
1. Правильно ли я думаю про то, как вытаскивать данные из потока, или есть какой-то более правильный способ. Если есть способ, подскажите его, а если нет, то подскажите, как дотянуться из потока backgroundworker-bw_statusUp до данных класса в потоке backgroundworker-bw_clientReceining.
2. В случае отключения клиента, как мы отключаем клиента
Код
clientSocket.Close();
Верно?
А как нам остановить именно тот поток, от которого отключился клиент. Не понимаю.

Уважаемые, очень надеюсь на Вашу помощь. Спасибо.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.04.2015, 09:19
Ответы с готовыми решениями:

Проверка на стороне сервера, что клиент обработал отправленные данные
Есть клиент и есть сервер, общаются по именованому каналу (named pipe) Проблема: нужно сделать...

Как получить данные от клиентов socket сервером?
Вот, что я сделал: IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName()); ...

Описать структуру с полями, считать данные из текстового файла, вывести данные, подсчитать количество
Доброе утро. С C# я знаком весьма посредственно, однако появилась необходимость выполнить на нем...

Возможно ли передавать синхронно данные между клиентом и сервером?
Всем привет. Пытаюсь сделать отдельный сервер для Unity3D. Мне нужно, чтобы клиент передавал данные...

8
[Bicycle Reinventor]
322 / 260 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
29.04.2015, 09:41 2
у Вас, уважаемый, каша. Как в коде, так и в понятиях.
Цитата Сообщение от best_vint Посмотреть сообщение
Хочу в массив выводить данные-ид клиента, данные серверу и данные отправленные сервером.
В массив чего? Какого типа? И зачем вообще это нужно?
Цитата Сообщение от best_vint Посмотреть сообщение
-передаёт clientNO-то есть я думал это использовать в качестве идентификатора строки массива
Что вы подразумеваете под "идентификатор строки массива"? Индекс? Значение? Что-то иное?
Цитата Сообщение от best_vint Посмотреть сообщение
Единственное решение, которое пришло в голову, это создать ещё один backgroundworker-bw_statusUp и в нём бесконечный цикл сделать
Есть давно написанные шаблоны для сервера и клиента на TCP, почему вы не используете их?
Цитата Сообщение от best_vint Посмотреть сообщение
2. В случае отключения клиента, как мы отключаем клиента
C#
1
clientSocket.Close();
Верно?
Перед закрытием клиента следует закрыть его Stream.
C#
1
clientSocket.GetStream().Close();
0
2 / 2 / 2
Регистрация: 08.11.2014
Сообщений: 35
29.04.2015, 11:03  [ТС] 3
По поводу каши, возможно, что где прочитал, такие и понятия)
Динамические массивы я создаю:
Код
        private List<string> DataClientToServerID = new List<string>();
        private List<string> DataClientToServerStatus = new List<string>();
        private List<string> DataServerTOClientStatus = new List<string>();
Зачем? чтобы видеть какие клиенты подключены, и вообще дальше писать и отлаживать программу, так удобнее. Хочу потом эти массивы в datagridview выводить.
Идентификатор строки массива-под этим понятием подразумеваю индекс.
Про существование шаблонов-возможно, просто я тему создал в c# для начинающих, поэтому очень многого не знаю и не понимаю
Спасибо.
0
[Bicycle Reinventor]
322 / 260 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
29.04.2015, 13:46 4
Лучший ответ Сообщение было отмечено best_vint как решение

Решение

Вот код, повыбрасывал всё лишнее.
Кликните здесь для просмотра всего текста

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    class Server : BackgroundWorker
    {
        private TcpListener listener;
        private List<Connection> connections;
        private bool exit;
 
        public Server(int port)
        {
            listener = new TcpListener(IPAddress.Any, port);
            listener.Start();
        }
 
        private void Message(string message)
        {
            Console.Write(DateTime.Now.ToLongTimeString() + ": " + message);
        }
 
        public void Broadcast(string message)
        {
            for (int i = 0; i < connections.Count; i++)
            {
                if (connections[i].currentState == Connection.State.Authorized)
                    connections[i].Write(message);
            }
        }
 
        protected override void OnDoWork(DoWorkEventArgs e)
        {
            Message("Сервер стартовал\n");
 
            while (true)
            {
                Thread.Sleep(1);
                if (exit) return;
 
                try
                {
                    if (listener.Pending())
                    {
                        TcpClient client = listener.AcceptTcpClient();
                        Message("Подключился клиент: " + client.Client.RemoteEndPoint.ToString() + "\n");
                        Connection c = new Connection(client, this);
                        connections.Add(c);
                        c.onBroadcast += new EventHandler<ObjectEventArgs>(c_onBroadcast);
                        c.onClose += new EventHandler<ObjectEventArgs>(c_onClose);
                    }
                }
                catch (Exception err)
                {
                    Message("Сервер сообщает об ошибке: " + err.Message + "\n");
                    continue;
                }
            }
        }
 
        void c_onClose(object sender, ObjectEventArgs e)
        {
            Connection c = sender as Connection;
            c.Exit();
            connections.Remove(c);
        }
 
        void c_onBroadcast(object sender, ObjectEventArgs e)
        {
            Broadcast(e.value.ToString());
        }
 
        public void Exit()
        {
            exit = true;
        }
    }
 
    class Connection
    {
        public enum State
        {
            WaitForLogin = 0,
            WaitForPassword = 1,
            Authorized = 2
        }
        public State currentState { get; private set; }
        private Server server;
        private TcpClient client;
        private NetworkStream stream;
        private Thread communicatingThread;
        private Random rnd;
 
        private byte[] sessionID;
        private string ip;
        private string port;
        private int wrongPasswordsAttempt;
        private bool exit;
 
        public event EventHandler<ObjectEventArgs> onBroadcast = delegate { };
        public event EventHandler<ObjectEventArgs> onClose = delegate { };
 
        public Connection(TcpClient client, Server server)
        {
            currentState = State.WaitForLogin;
            this.server = server;
            this.client = client;
            ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
            port = ((IPEndPoint)client.Client.RemoteEndPoint).Port.ToString();
            stream = client.GetStream();
            communicatingThread = new Thread(new ThreadStart(Communicating));
            communicatingThread.IsBackground = true;
            communicatingThread.Start();
            rnd = new Random();
        }
 
        private void Message(string message)
        {
            Console.Write(DateTime.Now.ToLongTimeString() + ": " + message);
        }
 
        private void Communicating()
        {
            string input = String.Empty;
            byte[] message = new byte[0];
 
            Message("Поток соединения " + ip + ":" + port + " стартовал\n");
 
            while (true)
            {
                if (exit) break;
                Thread.Sleep(1);
 
                try
                {
                    if (stream.CanRead)
                    {
                        message = new byte[0];
                        if (stream.DataAvailable)
                        {
                            byte[] buffer = new byte[65535];
 
                            using (MemoryStream messageStream = new MemoryStream())
                            {
                                while (stream.DataAvailable)
                                {
                                    int bytesRead = stream.Read(buffer, 0, buffer.Length);
                                    messageStream.Write(buffer, 0, bytesRead);
                                }
 
                                message = messageStream.ToArray();
                            }
                        }
 
                        if (message.Length > 0)
                        {
                            switch (currentState)
                            {
                                case State.WaitForLogin:
                                    input = Encoding.UTF8.GetString(message);
                                    CheckLogin(input);
                                    break;
 
                                case State.WaitForPassword:
                                    CheckPassword(message);
                                    break;
 
                                case State.Authorized:
                                    input = Encoding.UTF8.GetString(message);
                                    Message(String.Format("[{0} {1}:{2}]: {3}\n", currentAccount.Login, ip, port, input));
                                    onBroadcast(this, new ObjectEventArgs(String.Format("[{0}]: {1}\n", currentAccount.Login, input)));
                                    break;
 
                                default:
                                    throw new Exception(String.Format("Соединение оказалось в неизвестном состоянии и будет закрыто\n"));
                            }
                        }
                    }
                    if (client.Client.Poll(0, SelectMode.SelectRead))
                    {
                        byte[] checkConn = new byte[1];
                        if (client.Client.Receive(checkConn, SocketFlags.Peek) == 0)
                        {
                            Message("Клиент " + ip + ":" + port + " отключился\n");
                            break;
                        }
                    }
                }
                catch (Exception err)
                {
                    Message(String.Format("Соединение {0}:{1} сообщает об ошибке:{2}\n", ip, port, err.Message));
                    break;
                }
            }
 
            Message("Соединение " + ip + ":" + port + " закрывается\n");
            stream.Close();
            client.Close();
            Message("Поток соединения " + ip + ":" + port + " завершился\n");
            onClose(this, null);
        }
 
        public void Write(string message)
        {
            try
            {
                byte[] bytes = Encoding.UTF8.GetBytes(message);
                stream.Write(bytes, 0, bytes.Length);
            }
            catch (IOException) { return; }
        }
 
        public void Write(byte[] buffer)
        {
            try
            {
                stream.Write(buffer, 0, buffer.Length);
            }
            catch (IOException) { return; }
        }
 
        public void Exit()
        {
            exit = true;
        }
    }
 
 
    class ObjectEventArgs : EventArgs
    {
        public object value { get; private set; }
 
        public ObjectEventArgs(object arg)
        {
            value = arg;
        }
    }

Берите и добавляйте свою функциональность.
1
2 / 2 / 2
Регистрация: 08.11.2014
Сообщений: 35
29.04.2015, 14:45  [ТС] 5
Exerion, спасибо) Код большой, кое что понял. Клиентов разделяете по ip и порту. Exerion, а всё таки, для моего кода, можете подсказать, как мне получать доступ к свойствам класса handleClient client = new handleClient()-(созданном в потоке bw_clientReceining) из другого потока, или вообще теле таймера например, меня бы устроило.
Спасибо.

Добавлено через 13 минут
Цитата Сообщение от best_vint Посмотреть сообщение
вообще теле таймера например
*из тела таймера например
0
[Bicycle Reinventor]
322 / 260 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
29.04.2015, 15:43 6
Цитата Сообщение от best_vint Посмотреть сообщение
Код большой, кое что понял. Клиентов разделяете по ip и порту.
Не только. В полной версии кода у каждого соединения есть ещё и экземпляр класса "аккаунт", который содержит дополнительные сведения после успешной авторизации пользователя.
Цитата Сообщение от best_vint Посмотреть сообщение
как мне получать доступ к свойствам класса handleClient client = new handleClient()-(созданном в потоке bw_clientReceining) из другого потока, или вообще теле таймера например
Вы продолжаете плавать в понятиях. Вам следует очень внимательно повторить тему ООП, а конкретно - инкапсуляцию.
Не имеет значения, в каком потоке был создан объект. Имеет значение, в каком классе он был создан, и какой модификатор доступа при этом использовался. И имеет ли экземпляр класса-аксессора ссылку на экземпляр класса, содержащего интересующий объект.
А потоки тут вообще ни при чём.
0
2 / 2 / 2
Регистрация: 08.11.2014
Сообщений: 35
29.04.2015, 16:20  [ТС] 7
Exerion , вы правы, поток тут не причём. Смотрите, у меня в потоке цикл:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
            TcpListener serverSocket = new TcpListener(8888);
            TcpClient clietnSocket = default(TcpClient);
            serverSocket.Start();
            bw_clientReceining.ReportProgress(1);
            while (true | !bw_clientReceining.CancellationPending)
            {
                counterClient++;
                clietnSocket = serverSocket.AcceptTcpClient();
                handleClient client = new handleClient();
                client.startClient(clietnSocket, Convert.ToString(counterClient));
                _messageFromServer=client.dataout;
                bw_clientReceining.ReportProgress(2);
            }
            clietnSocket.Close();
            serverSocket.Stop();
соответственно до переменной client я могу дотянуться только в цикле while, а можно ли с этим что-то сделать?
0
[Bicycle Reinventor]
322 / 260 / 109
Регистрация: 19.10.2011
Сообщений: 668
Записей в блоге: 2
29.04.2015, 16:32 8
handleClient client - локальная переменная, объявленная в контексте метода, и даже более того - в блоке while. Разумеется, доступа к ней извне не будет, более того - после завершения работы этого метода данная переменная будет отмечена сборщиком мусора, как неиспользуемая, и рано или поздно будет уничтожена.
Возможное решение зависит от того, откуда вы хотите иметь доступ к данной переменной.
Если вы хотите получить доступ к данной переменной из другого метода этого же класса, сделайте переменную полем класса:
C#
1
private handleClient client;
Но в таком случае при каждом новом соединении данная переменная будет пересоздаваться.
Если вы внимательно посмотрите приведённый мною выше код, вы заметите, что ваш класс handleClient и мой класс Connection похожи по назначению. Далее, если вы проследите за тем, как я создаю новые экземпляры Connection при подключении клиентов к серверу, вы увидете, что у меня в классе сервера есть список private List<Connection>, куда они все и заносятся. Вот к нему доступ получить легко из любого место класса Server.
Если же вам нужно получить доступ к этому полю из другого класса - необходимо написать свойство:
C#
1
2
3
4
public List<Connection> Connections
{
   get {return connections;}
}
1
2 / 2 / 2
Регистрация: 08.11.2014
Сообщений: 35
30.04.2015, 08:30  [ТС] 9
Exerion спасибо, а по поводу записи свойств через get это умею)))
по поводу private и внутри класса, это уж совсем озы)
буду с Вашим примером разбираться Connection,потому что я так понял, это единственный для меня выход, который кстати решает много моих проблем.

Добавлено через 2 часа 57 минут
Exerion ещё раз спасибо, сразу не догадался искать Connections.add попробую у себя в коде так же сделать

Добавлено через 12 часов 51 минуту
Exerion всё получилось, решились все мои проблемы с доступом к данным, я тупил, да и на тему списков(массивов) в голове прибавилось.
Сделал по вашему подобию:
Код
private List<string> ProxyList = new List<string>();
Ну и в цикле добавил:
Код
connections.Add(client);
Теперь в класс только свойства добавлять
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.04.2015, 08:30

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь или здесь.

Вывести данные из List (в листе структура Struct (в структуре данные формата int, short, byte) в textBox
Не выводятся данные

Введенные данные структуры не проходят проверку в конце (if (Sum/7 >= new_midsumma) и просто все эти данные выводят
Задание: Описать структуру с именем «Студенты», содержащую следующие поля: фамилия и инициалы;...

Записать данные в файл и просмотреть данные из файла
Протабулировать функцию y=sin(x + x2 ) для -2pi&lt;=x&lt;=2pi с шагом pi/10. Записать данные в файл и...

Межпроцессорные данные. Общие данные 2х разных приложений
Ребятки, есть вопрос. Как передать 1 и туже переменную, созданную в одном процессе (приложении) в...


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

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

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