7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
1

Прием данных клиентом TcpClient, данных попадается некорректные значения, почему?

14.11.2015, 14:56. Показов 1697. Ответов 19
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Есть сервер на си, который шлет ответ клиенту, вот тестовый кусок:

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
struct recv_packet
{
    int magic;
    int code;
    int length;
    char *body;
 
};
 
char send_buff[1024+1] = "";
ZeroMemory(&send_buff, 1024);
memset(send_buff, 'A', 1024);
//send_buff[1024] = '\0';
recv_packet rcv_pkt = { 0 };
rcv_pkt.magic = MAGIC;
rcv_pkt.code = 0;
rcv_pkt.length = strlen(send_buff);
rcv_pkt.body = send_buff;
int size = sizeof(rcv_pkt.magic) + sizeof(rcv_pkt.code) + sizeof(rcv_pkt.length) + 1024+1;
 
 
if (send(ClientSocket, (char *)&rcv_pkt, size, 0) == SOCKET_ERROR)
{
    printf("Error %d\n", WSAGetLastError());
    closesocket(ClientSocket);
    WSACleanup();
    return 1;
}
Клиент на с# принимает данные вот так:

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
public struct recv_packet
        {
            public int magic;
            public int code;
            public int length;
            public byte[] body;
 
        };
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            int port = 4000;
            TcpClient client = new TcpClient("127.0.0.1", 4000);
            NetworkStream nws = client.GetStream();
            BinaryWriter bw = new BinaryWriter(nws);
            BinaryReader br = new BinaryReader(nws);
            byte[] buff = new byte[512];
 
            send_packet pkt = new send_packet();
            pkt.magic = magic;
            pkt.cmd = (int)command.MOVE_MOUSE;
            while (true)
            {
 
                bw.Write(pkt.magic);
                bw.Write(pkt.cmd);
               
                //br.Read(buff, 0, 512);
                recv_packet rcv_pkt = new recv_packet();
                rcv_pkt.magic = br.ReadInt32();
                rcv_pkt.code = br.ReadInt32();
                rcv_pkt.length = br.ReadInt32();
                rcv_pkt.body = br.ReadBytes(rcv_pkt.length);
                //string str = rcv_pkt.length.ToString();
                string str = System.Text.Encoding.Default.GetString(rcv_pkt.body);
               
                MessageBox.Show(str);
               
                
            }
Не дело в том что в отладчике в rcv_pkt.body первыми идут какие-то другие байты, а не "65" как должно быть. Почему так происходит? На сервере в отладичке все тело ответа заполнено "А".
И вообще, может я не так данные принимаю и есть способ адекватнее?
Миниатюры
Прием данных клиентом TcpClient, данных попадается некорректные значения, почему?  
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.11.2015, 14:56
Ответы с готовыми решениями:

Сокеты. Прием данных клиентом от сервера
Здравствуйте. Задача такая: Клиент отправляет серверу данные, сервер, исходя из полученных данных,...

Прием данных Winsock и преобразование данных Byte в String
VB.NET Здравствуйте! Вопрос! Есть обьект winsock для обмена сообщениями tcp\ip....

Найти минимальный элемент массива. Прием данных, как указатель на начало масива, и как копию данных
Дана задача. Задан масив чисел , без знака. Нужно написать групу процедур которые будут находить...

Почему значения получаются одни и те же, при вводе разных данных?
Почему значения получаются одни и те же, при вводе разных данных? using System; using...

19
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
14.11.2015, 23:15 2
А вы пробовали сачала прочитать полученные данные, а потом уже отправлять? А то вы сначала пишете в поток, а потом из него читаете, мне кажется это может вызвать проблемы как у вас.
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
14.11.2015, 23:23  [ТС] 3
Спасибо за внимание к теме. Но суть в том что мне нужно сначала отправить данные потом получить. С основной проблемой я более-менее разобрался, теперь данные приходят от сервера нормально, но вот при посылке происходит что-то странное.
Вот часть, отвечающая за прием данных:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
struct send_packet
{
    int magic;
    int cmd;
};
 
iResult = recv(ClientSocket, buff, BUFLEN, 0);
if (iResult > 0)
{
    send_packet *pkt;
    pkt = (send_packet *)buff;
    printf("magc %d  cmd %d\n", pkt->magic, pkt->cmd);
    printf("Received %d %s\n", iResult, buff);
Я отсылаю на сервер структуру по-частям:
C#
1
2
bw.Write(pkt.magic);
bw.Write(pkt.cmd);
И сервер должен отобразить "magc 101 cmd 2". А у меня получается что сервер может отобразить "magc 2 cmd 0"
и "magc 0 cmd 2". Непонятно почему так происходит. Может дело в том что нельзя так последовательно отсылать данные через binarywriter? Но как тогда структуру отослать? Причем это касается в особенности структур с полем, которое содержит неизвестное заранее количество байт.
0
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
14.11.2015, 23:35 4
Данные не обязательно приходят целиком. Это нужно учитывать при получении. Нужно сначала долждаться получания всех данных, а потом уже их обрабатывать.

Вот у вас iResult может быть как 4, так и 8 байт, поэтому если вы ожидаете 8 байт, нужно принимать пока не будут получены все 8 байт, и только потом уже их как-то обрабатывать.
2
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
14.11.2015, 23:40  [ТС] 5
Да, 8 байт это в примере, вообще я буду использовать структуру с полями переменной длинны, поэтому тут, наверное, на количество байт не положится. Но вот этот код
C#
1
2
bw.Write(pkt.magic);
bw.Write(pkt.cmd);
сразу шлет все данные или последовательно? Можно как-то сделать отправку единовременно или для этого нужен send() какой-нибудь?
0
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
15.11.2015, 00:04 6
Независимо от того как вы отправляете данные, они могут быть получены на другом конце частями. Поэтому это нужно учитывать и писать код который не сломается если данные пришли не полностью.
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
15.11.2015, 00:05  [ТС] 7
Но если данные переменной длины?
0
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
15.11.2015, 00:12 8
Ну а как вы думаете что нужно сделать?
Hint: обычно в начале отправляют длинну данных.
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
15.11.2015, 00:14  [ТС] 9
Но мне сначала нужно отправить идентификатор пакета (magic). А потом уже остальные данные. Мне кажется еще какой-то вариант должен быть, чтобы не отталкивается от результата recv(), не?
0
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
15.11.2015, 00:24 10
Цитата Сообщение от young_snake Посмотреть сообщение
Но мне сначала нужно отправить идентификатор пакета (magic)
Отправляйте. Он же у вас не переменного размера?
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
15.11.2015, 10:12  [ТС] 11
Нет, тогда странно получается. Зачем нужны структуры данных если все равно по кусочку их отправлять придется.
0
1643 / 1144 / 171
Регистрация: 23.07.2010
Сообщений: 6,794
15.11.2015, 12:00 12
Цитата Сообщение от young_snake Посмотреть сообщение
Зачем нужны структуры данных если все равно по кусочку их отправлять придется.
отправляют целиком. Принимают частями, но протокол гарантирует доставку. Посему - маркер начала и конца сообщения (как правило STX и ETX)
http://www.theasciicode.com.ar... ode-2.html
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
15.11.2015, 12:11  [ТС] 13
Так, тогда я запутался. Получается что нужно сначала отправить байт с STX, потом структуру, потом ETX. На принимающей стороне читать сокет, потом искать в приемном буфере ETX, и если его нет, то скидывать данные во временный буфер, потом читать еще, и делать так пока ETX не получу? Какая-то непростая схема получается.
0
1643 / 1144 / 171
Регистрация: 23.07.2010
Сообщений: 6,794
15.11.2015, 12:48 14
именно. Причем учитывая, что с ETX ты можешь получить еще и STX со своим ETX
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
15.11.2015, 13:40  [ТС] 15
Как это, в каком случае такое может произойти? (И что тогда делать =\)
0
1643 / 1144 / 171
Регистрация: 23.07.2010
Сообщений: 6,794
15.11.2015, 13:54 16
разбирать цепочки, что делать. если ты отправил <STX>lfsdlkjfshlkfjgdfsk<ETX><STX>slkfjhslkfjhslkfhjsd<ETX>
протокол гарантирует доставку, но необязательно целиком, возможно частями
1
Эксперт .NET
6452 / 4053 / 1599
Регистрация: 09.05.2015
Сообщений: 9,487
15.11.2015, 16:49 17
STX/ETX тут совсем не обязательны, можно просто указывать длинну.
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
15.11.2015, 17:30  [ТС] 18
Я понял, наверное так и придется поступить. Потому что других адекватных путей пока не видно.
0
1643 / 1144 / 171
Регистрация: 23.07.2010
Сообщений: 6,794
16.11.2015, 09:09 19
Цитата Сообщение от Someone007 Посмотреть сообщение
STX/ETX тут совсем не обязательны, можно просто указывать длинну.
хе-хе. Где гарантия, что второй (третий,пятый) байт придут вместе с первым?
0
7 / 7 / 2
Регистрация: 26.12.2011
Сообщений: 269
16.11.2015, 12:43  [ТС] 20
Как и писал Someone007, придется ждать пока пакет целиком не прочитается, а потом уже смотреть че там пришло.

C++
1
2
3
4
5
6
7
8
9
10
ZeroMemory(&buff, BUFLEN);
int numRcvBytes = 0;
while (numRcvBytes < sizeof(send_packet))
{
    iResult = recv(ClientSocket, buff + numRcvBytes, BUFLEN, 0);
    numRcvBytes += iResult;
}
numRcvBytes = 0;
 
//работа с данными
0
16.11.2015, 12:43
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
16.11.2015, 12:43
Помогаю со студенческими работами здесь

Отправка различных данных через TcpServer/TcpClient
Мне надо сделать приложение, которое через tcp будет передавать несколько каналов данных:2 видео,2...

Шифровка данных между клиентом и сервером
День добрый! (извините, коль кого обидел:)) Тема, может, и изъезженная, и всё же нужной...

Передача данных между клиентом и сервером
Имеется многопоточный сервер, как лучше реализовать передачу данных между клиентом и сервером?...

Передача данных между клиентом и сервером
Какого мембера этот код не работает? Все же вроде верно написано! index.html: &lt;!DOCTYPE...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru