Форум программистов, компьютерный форум, киберфорум
Наши страницы

C# .NET

Войти
Регистрация
Восстановить пароль
 
Vla00
7 / 7 / 3
Регистрация: 06.10.2012
Сообщений: 476
#1

Проблема с объединением сообщений при передаче по TCP - C#

18.04.2014, 22:43. Просмотров 470. Ответов 8
Метки нет (Все метки)

Вообщем делаю регистрацию и авторизацию клиента на сервере.
Клиент:
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
private void button1_Click(object sender, EventArgs e)
        {
            byte[] regist = new byte[256];
            string reg = "register!";
 
            nameUser = textBox1.Text;
            passUser = textBox2.Text;
            if ((nameUser.Length > 1) || (passUser.Length > 1))
            {
                TcpClient client = new TcpClient("127.0.0.19", 2010);
                NetworkStream io = client.GetStream();
 
                regist = Encoding.UTF8.GetBytes(reg);
                io.Write(regist, 0, regist.Length);
 
                regist = Encoding.UTF8.GetBytes(nameUser);   //логин
                io.Write(regist, 0, nameUser.Length);
                regist = Encoding.UTF8.GetBytes(passUser);   //пароль
                io.Write(regist, 0, nameUser.Length);
 
                io.Read(regist, 0, 1);
                if(regist[0] == 1)
                {
                    status.ForeColor = Color.Green;
                    status.Text = "Вы успешно зарегестрировались.";
                }
 
                client.Close();
            }
            else
            {
                status.ForeColor = Color.Red;
                status.Text = "Некорректно введены данные.";
            }
        }
Сервер:
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
while (true)
                {
 
                    string RegAwtor = null;
                    byte[] stop = new byte[100];
                    Console.WriteLine("Сервер ожидает {0}", listener.LocalEndpoint);
                    TcpClient client = listener.AcceptTcpClient();
                    NetworkStream io = client.GetStream();
 
                    Console.WriteLine("Принято соединение от {0}", client.Client.RemoteEndPoint);
 
                    i = io.Read(stop, 0, stop.Length);
                    RegAwtor = System.Text.Encoding.UTF8.GetString(stop, 0, i);
 
                    if (RegAwtor == "register!")
                    {
                        i = io.Read(stop, 0, stop.Length);
                        NameUser = System.Text.Encoding.UTF8.GetString(stop, 0, i);
                        i = io.Read(stop, 0, stop.Length);
                        PassUser = System.Text.Encoding.UTF8.GetString(stop, 0, i);
 
                        if (Register.registers(NameUser, PassUser) == 1)
                            StatusWork[0] = 1;
                        else
                            StatusWork[0] = 0;
 
                        io.Write(StatusWork, 0, StatusWork[0]);
 
                    }
                    else
                    {
                        if (RegAwtor == "avtoriza!")
                        {
                            
                        }
                        else
                        {
                            ZaprosPrivestvie(io);
                            DetaliZaprosa(io);
                        }
                    }
 
                    client.Close();
                }
Проблема в том что клиент сразу посылает сообщение что хочет зарегестрироваться и потом логит и пароль (всё отдельно). Но сервер принимает всё в одно сообщение:
Проблема с объединением сообщений при передаче по TCP
Почему он все сообщения пихает в одно? как это исправить? длина логина и пароля, всегда разные, так что считать определённое количество символов не пойдёт...
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.04.2014, 22:43
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Проблема с объединением сообщений при передаче по TCP (C#):

Потеря данных при передаче по TCP - C#
Система сложная, отслеживает и записывает все происходящее. В итоге получается вот что: сервер отправляет пакет (условный фрагмент из байт)...

Ошибка при передаче изображения по TCP - C#
Ошибка при передаче изображения по TCP? Клиент: Bitmap printscreen = new Bitmap(Screen.PrimaryScreen.Bounds.Width,...

Варьирование таймаута при передаче по TCP/IP - C#
Доброго дня! В общем есть задание, реализовать клиент серверное приложение, которое будет: 1. Передавать 32 кб информации,...

.NET 4.x Слияние сообщений при их передаче через TcpClient - C#
Доброго времени суток. Имеется подключение через TcpClient. Передача: public void SendMessage(string message) { ...

.NET 4.x Передача сообщений через TCP/IP - C#
Доброго времени суток. При разработке программы, столкнулся с двумя типами логики приложения при передаче сообщения: 1) Connect ->...

.NET 3.x итерация при передаче аргументов в функцию - C#
Доброго времени суток хочу передать в функцию аргумент итерируемый при передаче то есть чтобы это выглядело так : ...

8
WizarД
53 / 56 / 2
Регистрация: 07.02.2011
Сообщений: 556
Записей в блоге: 1
18.04.2014, 23:12 #2
Vla00, Поэтому для игр пишут свою архитектуру данных.
Смотрите в сторону BinaryReader.
Они позволят вам создавать пакеты, указывать их ID, длину. А так же не придется мучатся со сливанием данных.

Добавлено через 7 минут
либо же попробуйте, это поможет вам сбрасывать данные на сервер после записи.
C#
1
io.Flush();
0
Убежденный
Ушел с форума
Эксперт С++
15697 / 7207 / 1139
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
19.04.2014, 12:21 #3
Цитата Сообщение от Vla00 Посмотреть сообщение
Почему он все сообщения пихает в одно?
Потому что в TCP нет сообщений. Нет пакетов, нет границ.
TCP - это поток данных, который можно читать и писать кусками
неопределенных размеров. И работать с ним нужно исходя из этого.

Цитата Сообщение от Vla00 Посмотреть сообщение
как это исправить?
Разработать свой (или взять готовый) протокол, работающий поверх TCP и
имеющий нужное поведение. Например, HTTP. Или передавать длину
данных, а затем сами данные. Или передавать в потоке данных какой-то
специальный байт-разделитель, сообщающий, что в данном месте одно
сообщение заканчивается и начинается следующее. И т.п.
0
lawliet93
17 / 5 / 0
Регистрация: 22.03.2011
Сообщений: 329
20.04.2014, 01:05 #4
Я недавно создавал тему с таким же вопросом. Чувак Убежденный верно написал. Слушай истину. TCP гарантирует лишь доставку и очередность. То есть, если ты сначала отправишь логин, а потом пароль, то сначала придет логин, а потом пароль, но никак иначе. НО! Если ты отправляешь сначала 20 байт, а потом 30, то может прийти одно сообщение длиною в 50 байт, или же другое любое количество, например, 3 сообщения 10 20 и 20 байт. С первым ты уже столкнулся, со вторым еще нет, я тоже со вторым случаем не стыкался еще, поэтому не запилил решение для него. А вот для первого запилил. Во-первых, твой вариант сериализации слишком кривой. C# эт тебе не C какой-то и ты можешь использовать такую штуку, как BinaryFormater и сериализировать целые классы. Например, тебе нужно отправить логин и пароль, для этого ты можешь создать класс или структуру с полями login и password, занести в эти поля нужные значение и с помощью BinaryFormater почти что одной строкой превратить эту структуру или класс в массив байт и отправить, а на другой стороне можешь так же легко десериализовать принятые данные. Во-вторых, перед отправкой каждого сообщения нужно дописывать его длину в начало сообщения. Например, у тебя есть 20 байт, которые нужно отправить, ты берешь эту длинну, ну то есть buffer.length (это будет число типа int) и сериализируешь его в массив байт, он будет длиною в 4 байта, то есть тебе нужно создать массив байт длиною в 24 байта, в первые 4 байта записать длину последующих данных, а далее идут сами данные. А на сервере, когда примешь данные, сначала берешь первые 4 байта и переводишь в int, а далее смотришь, если длина принятых байт больше чем 4+длина данных, то значит пришло 2 сообщения, и нужно как-то это обработать... я сделал вот так
надеюсь, ты разберешься, вместо типа int я тут использую ushort, который весит только 2 байта вместо 4.
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
        private void ReceiveCallback(IAsyncResult result)
        {
            try
            {
                Client client = (Client)result.AsyncState;
                int nBytes = client.socket.EndReceive(result);
                SystemMessage("Received: " + nBytes + " bytes");
 
                if (nBytes > 0)
                {
                    lock (clients)
                    {
                        int fullLength = 0, dataLength = 0;
                        int startIndex = 0;
                        do
                        {
                            dataLength = BitConverter.ToUInt16(client.bufferReceive, startIndex);
 
                            byte[] arr = new byte[dataLength];
                            Buffer.BlockCopy(client.bufferReceive, startIndex + 2, arr, 0, dataLength);
                            ClientData command = Serializer.Deserialize<ClientData>(new MemoryStream(arr));
                            ServerData result1 = new SuperExecutor(clients, client, timer).Executor(command);
 
                            switch (result1.SendingMode())
                            {
                                case SelectSending.SendToSelf:
                                    SendToSelf(client, result1);
                                    break;
                                case SelectSending.SendToOthers:
                                    SendToOthers(client, result1);
                                    break;
                                case SelectSending.SendToClient:
                                    SendToClient(result1);
                                    break;
                                case SelectSending.NoSend:
                                    break;
                            }
 
                            fullLength = dataLength + 2;
                            startIndex += fullLength;
 
                            SystemMessage("length: " + dataLength + "  full length: " + fullLength + "  start index: " + startIndex);
 
                        } while (startIndex < nBytes);
                    }
                }
 
                if (nBytes == 0)
                {
                    client.socket.Close();
                    lock (clients)
                    {
                        clients.Remove(client);
                        SystemMessage("Client has been removed");
                    }
                }
                if (clients.Contains(client))
                    client.socket.BeginReceive(client.bufferReceive, 0, client.bufferReceive.Length, SocketFlags.None,
                        new AsyncCallback(ReceiveCallback), client);
            }
            catch (SocketException e)
            {
                SystemMessage(e.Message + " ErrorCode: " + e.ErrorCode);
            }
            catch (Exception e)
            {
                SystemMessage(e.Message + " | ReceiveCallback");
            }
        }
И еще одно, если ты пишешь игру, и не пошаговую какую-то, а ммо экшон, то тебе придется освоить UDP
0
Psilon
Master of Orion
Эксперт .NET
5908 / 4805 / 634
Регистрация: 10.07.2011
Сообщений: 14,407
Записей в блоге: 5
Завершенные тесты: 4
20.04.2014, 16:36 #5
Цитата Сообщение от lawliet93 Посмотреть сообщение
Слушай истину.

Не по теме:

это сильно

0
WizarД
53 / 56 / 2
Регистрация: 07.02.2011
Сообщений: 556
Записей в блоге: 1
20.04.2014, 19:55 #6
Цитата Сообщение от lawliet93 Посмотреть сообщение
И еще одно, если ты пишешь игру, и не пошаговую какую-то, а ммо экшон, то тебе придется освоить UDP
Вовсе не обязательно. Почему не использовать TCP?
0
Yukikaze
340 / 319 / 19
Регистрация: 12.12.2011
Сообщений: 563
20.04.2014, 20:03 #7
Цитата Сообщение от lawliet93 Посмотреть сообщение
И еще одно, если ты пишешь игру, и не пошаговую какую-то, а ммо экшон, то тебе придется освоить UDP
далека не факт, L2, WoW, PW, Archeage все они достаточно большие и работают по TCP. UDP чаще используют в шутерах, где скорость отклика важнее, по этому в CS при рассинхроне лагеры начинают телепортироваться по карте
0
lawliet93
17 / 5 / 0
Регистрация: 22.03.2011
Сообщений: 329
20.04.2014, 20:32 #8
Yukikaze, ну так все перечисленные игры не относятся к жанру экшон
0
Vla00
7 / 7 / 3
Регистрация: 06.10.2012
Сообщений: 476
23.04.2014, 20:10  [ТС] #9
Мне нужно создать socks v5 клиент-сервер.
Проблему решил объединением строк, а на сервере разбивал принятую строку на пробелы и далее уже массив анализировал как мне нужно...
0
23.04.2014, 20:10
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.04.2014, 20:10
Привет! Вот еще темы с ответами:

Ошибка при передаче данных в GridView - C#
Среда: WPF Ошибка: Произошла ошибка базового поставщика в Open. Код: private void Window_Loaded(object sender,...

Смысл ref при передаче ссылочного типа - C#
Друзья, обременился таким вопросом. Кто что скажет? Когда через ref передаем структуру это понятно. Но какой она имеет смысл для...

Ошибка в имени файла при передаче по e-mail - C#
Здравствуйте. Пишу программу частичным заданием которой является отправка файла по почте. При этом имя файла зависит от результатов...

Теряются байты при передаче массива структур клиенту - C#
Здравствуйте. Сервер подаёт на клиент массив структур. размер структуры 148байт. т.е всего 4400байт Получаю данные чз BeginReceive....


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

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

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