Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 10, средняя оценка - 4.90
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
#1

Клиент-сервер, артефакты с DataAvailable - C#

17.03.2012, 16:48. Просмотров 1422. Ответов 13
Метки нет (Все метки)

В общем, есть сервер который отправляет команды клиенту. Команд много, одна из них заставляет клиента отправлять в цикле foreach строки типа
C#
1
-setdir|C:\Program Files
Изначально сервер настраивался как отправитель, но потом понадобилось принять от клиента информацию. Полазил в MSDN и нашел свойство DataAvailable в классе NetworkStream. Это свойство возвращает значение указывающее есть ли в потоке данные которые можно прочитать.

Тоесть я пишу:

C#
1
2
3
4
if(Stream.DataAvailable == true)
{
//выполняю чтение информации из потока на сервере.
}
Все должно происходить так: Сервер отправляет команду клиенту, клиент отправляет информацию серверу, сервер смотрит что в потоке есть информация и производит чтение, да вот только DataAvailable по непонятным причинам всегда возвращает false, что настораживает.

Как мне быть?

Клиент:
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
class Program
{       
    public static System.Net.Sockets.TcpClient Client;
    public static System.Net.Sockets.NetworkStream Stream;
    public static byte[] Data = new Byte[1024];
    public static void Main()
    {
        try
        {
            while (true) 
            {   
                Client = new System.Net.Sockets.TcpClient("10.10.200.48", 8547);
                Stream = Client.GetStream();
            
                    Int32 bytes = Stream.Read(Data, 0, Data.Length);
                    string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
                    Reading_instruction(ResponseData);  
                }
            } 
            catch (Exception ex)
            {
                Console.WriteLine("Ошибка: {0}", ex.Message);
                Main();
            }
        }
    }       
    static void Reading_instruction(string Command)
    {
        string[] CommandLine = null;
        if (Command.ToLower().StartsWith("-getdir"))
        {
            CommandLine = Command.Split('|');
            string[] DirRead = System.IO.Directory.GetDirectories(CommandLine[1]);
            Stream = Client.GetStream();
            foreach (string Dir in DirRead) 
            {
                Stream.Write(System.Text.UnicodeEncoding.UTF8.GetBytes("-setdir|" + Dir), 0, System.Text.UnicodeEncoding.UTF8.GetBytes("-setdir|" + Dir).Length);
            }
        }
    }
}
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
class Program
{
    public static System.Net.Sockets.TcpClient Client;
    public static System.Net.Sockets.NetworkStream Stream;
    public static byte[] Data = new Byte[1024];
    public static System.Net.IPAddress IP;
    public static System.Net.Sockets.TcpListener Server;
    
    public static void Main()
    {
        try 
        {
            IP = System.Net.IPAddress.Parse("10.10.200.48");
            Server = new System.Net.Sockets.TcpListener(IP, 8547);
            Server.Start();
            while (true)
                {
                Client = Server.AcceptTcpClient();
                        Stream = Client.GetStream();
                        Console.WriteLine("Клиент готов! ");
                    string Command = Console.ReadLine();
                        Stream.Write(System.Text.UnicodeEncoding.UTF8.GetBytes(Command), 0, System.Text.UnicodeEncoding.UTF8.GetBytes(Command).Length);
                    
                        if(Stream.DataAvailable == true)
                        {
                            Int32 bytes = Stream.Read(Data, 0, Data.Length);
                            string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
                            Reading_instruction(ResponseData);
                        }
            }                   
        } 
        catch (Exception ex) 
        {
            Console.WriteLine("\nПроизошла ошибка {0}", ex.Message);
            Main();
        }
    }
    public static void Reading_instruction(string Commands)
    {
        string[] CommandLine;
        if(Commands.ToLower().StartsWith("-setdir"))
        {
            CommandLine = Commands.Split('|');
            foreach (string Command in CommandLine) 
            {
                Console.WriteLine(Command);
            }
        }
    }
}

http://www.cyberforum.ru/csharp-net/thread773608.html
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
17.03.2012, 16:48
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Клиент-сервер, артефакты с DataAvailable (C#):

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

Клиент-сервер. Клиент не принимает данные
Здравствуйте о светлейшие умы сего мира! Я работаю над одним проектом, а именно...

Клиент-Сервер. Удалённый сервер
Всем здравствуйте. Я заинтересовался написать клиент-сервер приложение....

Клиент и сервер
Здравствуйте, помогите пожалуйста!Есть клиент и сервер,которые взаимодействуют...

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

13
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 18:06 #2
Попробуй заменить на:
C#
1
2
3
4
5
6
7
8
9
while(!Stream.DataAvailable)
{
    
}
if (Stream.DataAvailiable) {
    Int32 bytes = Stream.Read(Data, 0, Data.Length);
    string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
    Reading_instruction(ResponseData);
}
но тут нужно быть уверенным, что клиент пошлет данные.

Добавлено через 12 минут
Основная проблема, с которой я столкнулся - это не полное понимание принципов работы с сокетами.
Я не знаю, на сколько Вы хорошо разбираетесь в них, поэтому приведу цитату, которая может быть поможет:
"Сокет — конечная точка связи двустороннего канала между 2 компьютерами.

Если мы соединим 2 сокета, то получим канал, через который можно передавать данные в обе стороны. Одна сторона канала называется сервером, другая — клиентом.
Для передачи/приема данных нужно открыть канал. В конце всех операций — закрыть."
"Потоковый сокет — это сокет, который состоит из потока байтов, который может быть двунапрямленным (в обе стороны). Он берет на себя всю ответственность о доставке данных и исправлении ошибок. Особенностью есть возможность передачи больших объемов данных. Использует протокол TCP (Transmission Control Protocol), именно который обеспечивает поступление данных на другую сторону в нужной последовательности и без ошибок.

Если вам важна точность доставки данных, или их объем — потоковые сокеты будут лучшим выбором."
0
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
17.03.2012, 18:09  [ТС] #3
Цитата Сообщение от Mega-xaxax Посмотреть сообщение
но тут нужно быть уверенным, что клиент пошлет данные.
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
public static void Main()
{
    try 
    {
        IP = System.Net.IPAddress.Parse("10.10.200.48");
        Server = new System.Net.Sockets.TcpListener(IP, 8547);
        Server.Start();
                while(!Stream.DataAvailable)
        {
                Client = Server.AcceptTcpClient();
                    Stream = Client.GetStream();
                    Console.WriteLine("Клиент готов! ");
                string Command = Console.ReadLine();
                    Stream.Write(System.Text.UnicodeEncoding.UTF8.GetBytes(Command), 0, System.Text.UnicodeEncoding.UTF8.GetBytes(Command).Length);
        }
        if (Stream.DataAvailable) 
        {
                Int32 bytes = Stream.Read(Data, 0, Data.Length);
            string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
                Reading_instruction(ResponseData);
        }                   
    } 
    catch (Exception ex) 
    {
        Console.WriteLine("\nПроизошла ошибка {0}", ex.Source);
        Main();
    }
}
System.NullReferenceExeption В экземпляре объекта не задана ссылка на объект
0
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 18:10 #4
У Вас в коде создаются новые сокеты для каждой передачи данный, поэтому если в коде клиента Вы посылаете данные через один потоковый сокет (а у Вас именно он), то на сервере этот сокет обрабатывается и ответ посылается через этот же сокет, тогда в коде клиента Вы должны обработать старый сокет, т.е. не создавать новый.

Добавлено через 36 секунд
Цитата Сообщение от CycleFunction Посмотреть сообщение
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
public static void Main()
{
    try 
    {
        IP = System.Net.IPAddress.Parse("10.10.200.48");
        Server = new System.Net.Sockets.TcpListener(IP, 8547);
        Server.Start();
                while(!Stream.DataAvailable)
        {
                Client = Server.AcceptTcpClient();
                    Stream = Client.GetStream();
                    Console.WriteLine("Клиент готов! ");
                string Command = Console.ReadLine();
                    Stream.Write(System.Text.UnicodeEncoding.UTF8.GetBytes(Command), 0, System.Text.UnicodeEncoding.UTF8.GetBytes(Command).Length);
        }
        if (Stream.DataAvailable) 
        {
                Int32 bytes = Stream.Read(Data, 0, Data.Length);
            string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
                Reading_instruction(ResponseData);
        }                   
    } 
    catch (Exception ex) 
    {
        Console.WriteLine("\nПроизошла ошибка {0}", ex.Source);
        Main();
    }
}
System.NullReferenceExeption В экземпляре объекта не задана ссылка на объект
Блок while() {} нужно оставить пустым

Вот таким должен быть Ваш блок try:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
                       IP = System.Net.IPAddress.Parse("10.10.200.48");
                        Server = new System.Net.Sockets.TcpListener(IP, 8547);
                        Server.Start();
                        while (true)
                        {
                                Client = Server.AcceptTcpClient();
                                Stream = Client.GetStream();
                                Console.WriteLine("Клиент готов! ");
                                string Command = Console.ReadLine();
                                Stream.Write(System.Text.UnicodeEncoding.UTF8.GetBytes(Command), 0, System.Text.UnicodeEncoding.UTF8.GetBytes(Command).Length);
                                
                                while(!Stream.DataAvailiable) {}
 
                                if(Stream.DataAvailable == true)
                                {
                                        Int32 bytes = Stream.Read(Data, 0, Data.Length);
                                        string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
                                        Reading_instruction(ResponseData);
                                }
                        }
1
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
17.03.2012, 18:14  [ТС] #5
Цитата Сообщение от Mega-xaxax Посмотреть сообщение
на сколько Вы хорошо разбираетесь в них
Недавно начал изучать.
0
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 18:14 #6
Этот while() ждет пока по тому же потоку будет принята информация от клиента
0
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
17.03.2012, 18:21  [ТС] #7
Цитата Сообщение от Mega-xaxax Посмотреть сообщение
Вот таким должен быть Ваш блок try:
Сервер данные принял! Прогресс! Да вот только если сервер отправляет команду клиенту которая не требует возврата информации клиент после выполнения команды не подключается к серверу. Сервре отправляет команду, и после того как клиент ее выполнит он должен сообщить серверу о готовности принять новую команду. Он этого не делает.
0
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 18:27 #8
В таком случае, сервер должен знать какая из команд требует ответа от клиента.
Т.е. у Вас будет что-то типа следующей конструкции:
C#
1
2
3
if (command == "hello") {
   while(!Stream.DataAvailiable) {}
}
Но тут есть подводные камни. Допустим, сервер в блоке while() ждет, пока поступят данные от клиента, но у клиента отвалился интернетовский шнур. В итоге сервер будет ждать вечно. Решение можно найти с помощью таймаутов, т.е. если по происшествии 10 секунд данные от клиента не пришли, то выходим из блока while(). А можно пойти другим путем: для каждой команды (до ее завершения) создаем новый поток, и если из контекста понятно, что от клиента новые данные больше не придут, то завершаем поток.
0
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
17.03.2012, 18:30  [ТС] #9
Цитата Сообщение от Mega-xaxax Посмотреть сообщение
сервер должен знать какая из команд требует ответа
Дело в том что сервер вообще никаких команд не знает. Он просто отправляет текст, а клиент его интерпритирует, и если честно я вас немного не понял.
0
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 18:35 #10
Почему не знает? У Вас же есть метод
C#
1
2
3
4
5
6
7
8
9
10
11
12
        public static void Reading_instruction(string Commands)
        {
                string[] CommandLine;
                if(Commands.ToLower().StartsWith("-setdir"))
                {
                        CommandLine = Commands.Split('|');
                        foreach (string Command in CommandLine) 
                        {
                                Console.WriteLine(Command);
                        }
                }
        }
Если я не ошибаюсь, то он находится на стороне сервера.
0
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
17.03.2012, 18:43  [ТС] #11
Этот метод выполняется только тогда, когда DataAvailable возвращает true.
И проверять команды перед отправкой кажется не очень хорошим вариантом.
0
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 19:24 #12
Вот смотрите, простой пример. У нас есть сервер, которому мы посылаем команды, в ответ от сервера бы получаем текст. Предположим, что мы хотим:
1) получить список файлов на сервере;
2) вывести на консоль содержимое файла в этой папке.

Что мы должны сделать...
Для начала, все общение с сервером должно проходить через один потоковый сокет до нашего отключения. Мы должны создать сервер, который принимает подключившегося клиента, это делается с помощью:

C#
1
2
3
4
5
Server = new System.Net.Sockets.TcpListener(IP, 8547);
Server.Start();
while(true) {
    System.Net.Sockets.TcpClient Client = Server.AcceptTcpClient();
}
Данный код ждет, пока подключиться клиент, как только клиент подключился, то он ждет следующего клиента, больше ничего не делая.

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

C#
1
2
3
public static void SpeakWithClient(System.Net.Sockets.TcpClient Client) {
   // здесь у нас есть объект Client, с ним мы будем общаться
}
Поскольку клиентов множество, то одним потоком нам не обойтись, поэтому мы должны обрабатывать каждого клиента отдельно, т.е. в отдельном потоке:

C#
1
2
3
4
5
6
7
Server = new System.Net.Sockets.TcpListener(IP, 8547);
Server.Start();
while(true) {
    System.Net.Sockets.TcpClient Client = Server.AcceptTcpClient();
    Thread t = new Thread(new ParameterizedThreadStart(SpeakWithClient));
    t.Start(Client);
}
Здесь мы передали потоку объект, больше ничего и не требуется.
Далее будем заниматься обработкой клиента.
Поскольку мы общаемся с клиентом, то весь код должен находиться в цикле while():

C#
1
2
3
4
5
6
public static void SpeakWithClient(System.Net.Sockets.TcpClient Client) {
   bool connected = true;
   while(connected) {
       // здесь общаемся с клиентом
   }
}
Предположим, что заканчивать общение с сервером мы будем с помощью команды "exit", поэтому допишем наш метод:

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
public static void SpeakWithClient(System.Net.Sockets.TcpClient Client) {
   bool connected = true;
 
   NetworkStream Stream = Client.GetStream(); // получаем поток, теперь все общение
   // будем реализовывать через него
 
   while(connected) {
       // здесь общаемся с клиентом
       if(Stream.DataAvailable == true)
       {
                Int32 bytes = Stream.Read(Data, 0, Data.Length);
                string ResponseData = System.Text.UnicodeEncoding.UTF8.GetString(Data, 0, bytes);
                Reading_instruction(ResponseData, connected); //здесь мы передаем connected
                // если connected изменилось в методе Reading_instruction на false, то мы выйдем из потока,
                // потому что условие while выполняется до тех пор пока connected равно true
        }
   }
}
 
public static void Reading_instruction(string Commands, out connected)
        {
                string[] CommandLine;
                if(Commands.ToLower().StartsWith("exit"))
                {
                        connected = false;
                }
        }
Ну вот как-то так, здесь в коде могут быть ошибки, не проверял, хотел описать логику, который воспользовался бы я в на Вашем месте

Добавлено через 20 минут
А чтобы иметь возможность отправлять клиентам сообщения, нужно иметь список всех клиентов и отправлять сообщения каждому по-отдельности:
C#
1
2
3
4
5
string command = Console.ReadLine();
for (int i = 0; i < Clients.Length; i++) {
    NetworkStream stream = Clients[i].GetStream();
    //ну а дальше записываем данные в поток
}
1
CycleFunction
10 / 10 / 1
Регистрация: 25.01.2012
Сообщений: 103
17.03.2012, 19:29  [ТС] #13
В общем все понятно. Завтра как только проснусь, начну соккеты зубрить. А то утро уже, котелок вообще не греет. Это мне в сторону TcpListener, TcpClient и NetworkStream копать надо?

Не по теме:

P.S. Спасибо за своевременную помощь, с этим тут иной раз проблеммы

0
Mega-xaxax
38 / 38 / 1
Регистрация: 11.03.2012
Сообщений: 95
17.03.2012, 19:38 #14
TcpListener - запускает сервер, заставляя прослушивать порт на входящие подключения

TcpClient - это клиент, подключившийся к серверу, который имеет IP-адресс и т.д.

NetworkStream - позволяет получать данные от конкретного клиента и отправлять данные конкретному клиенту

У Вас есть сервер, который позволяет клиентам подключаться.
Далее есть Console.ReadLine(), который считывает строку с командой.

Эту строку надо послать каждому подключившемуся TcpClient'у с помощью NetworkStream

С помощью NetworkStream нужно выслушать ответ от клиента на команду (лучше всего, чтобы ответ был на каждую команду от сервера, типа получил, все "ОК").

Ну а копайте в ту сторону, где возникают затруднения, все это работает в комплексе, поэтому понимать нужно всё
1
17.03.2012, 19:38
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
17.03.2012, 19:38
Привет! Вот еще темы с решениями:

Клиент - сервер
TCP клиент-сервер. Не получаю ответа от сервера. Сервер прикрепил внизу. ...

Клиент-сервер
Всем доброго времени суток. У меня возникла следующая проблема. Я не могу...

Сервер-клиент
При включении клиент определяет и отправляет на сервер совой IP-адресс....

Сервер-клиент
Здравствуйте, посоветуйте пожалуйста книги на тему создания сервер-клиент...


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

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

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