#c #linux #tcp
#c #linux #tcp
Вопрос:
Я пытаюсь реализовать протокол (T) LV через TCP, отправляя буферы протокола с клиента python и получая с помощью сервера C .
Мой код выглядит более или менее так:
char* buffer[RCVBUFSIZE];
int recvsize= 0;
// Filling my buffer with as much as possible.
while(true) {
if(recvsize == RCVBUFSIZE) {
break;
} else if(recvsize = recv(sock, buffer recvsize, sizeof(buffer)-recvsize, 0) < 1) {
break;
}
}
//Parsing LV protocol
while(true) {
unsigned short protosize= 0;
//Copy first two bytes into protosize
memcpy((char *) amp;protosize, buffer, sizeof(unsigned short));
if(protosize == 0) { break; } // Protocol indicates EOM be setting length to "0"
void* protomsg[protosize];
memcpy(protomsg, buffer sizeof(unsigned short), protosize);
int msglength= sizeof(unsigned short) protosize;
//Now I'll move the whole buffer to the left so that I don't have to keep track of where I'm at.
memmove(buffer, buffer msglength, RCVBUFSIZE-msglength);
protoMsg pm;
if(!pm.ParseFromArray(protomsg, protosize)) { break; } // Parsing failed.
// Do stuff with parsed message.
}
Теперь у меня есть несколько проблем:
- Цикл while, принимающий сообщение, никогда не завершается. Я подозреваю, что вызов recv блокируется, когда данных больше не осталось, в то время как я ожидал, что он вернется с ошибкой. Я нашел функцию выбора, чтобы проверить, есть ли что-то для чтения. Я попробую. Но когда я вызываю receive только один раз, чтобы пропустить эту проблему (полученное сообщение содержит ~ 10 байт, поэтому я ожидаю, что все будет собрано за один вызов.) У меня другая проблема:
- memcpy и memmove, похоже, работают не так, как ожидалось. В первом цикле короткое замыкание обрабатывается, как и ожидалось (я получаю то же значение, которое я отправляю на другую сторону), но затем все, что связано с анализом буфера протокола, завершается неудачей. Я что-то неправильно понял?
Редактировать: что касается комментария о ntohs — в настоящее время я передаю short как little-endian, забыл упомянуть об этом. (Кстати, я еще изменю это.)
Третье редактирование: теперь код работает, но мне пришлось изменить следующее:
char* buffer[RCVBUFSIZE];
int recvsize= 0;
// Filling my buffer with as much as possible.
while(true) {
if(recvsize == RCVBUFSIZE) {
break;
} else if((recvsize = recv(sock, buffer recvsize, sizeof(buffer)-recvsize, 0)) < 1) {
break;
} else if(recvsize > 1) {
unsigned short msglength= 0;
memcpy((char *) amp;msglength, buffer recvsize-sizeof(unsigned short), sizeof(unsigned short));
if(msglength == 0) { break; } // Received a full transmission.
}
}
Итак, сначала мне нужно было добавить скобки вокруг recvsize = recv()
оператора, а во-вторых, поскольку неблокирующий метод по какой-то причине не сработал, я сейчас проверяю, переводятся ли последние два переданных байта в 0 при чтении беззнакового короткого. Это, вероятно, приводит к проблеме, если я случайно прочитал 0, который не является полем длины. Вероятно, я начну другой вопрос об этом.
Я также перешел protomsg
на char[]
, но я не думаю, что это действительно что-то изменило. (У меня уже был синтаксический анализ, работающий с массивом void ..)
Комментарии:
1. Вы должны вызывать
ntohs
полученныйshort
(и вызыватьhtons
при его отправке — «Сеть к хосту, короткая» /»Хост к сети, короткая»)
Ответ №1:
Если получаемое вами сообщение всегда составляет около 10 байт и RCVBUFSIZE
больше, вы никогда не завершите работу, пока не произойдет ошибка чтения данных. Кроме того, buffer
переменная в вашем коде представляет собой массив RCVBUFSIZE
указателей, вероятно, не то, что вы хотите.
Измените свой код следующим образом:
#define MINIMALMESSAGESIZE 10 // Or what the size may be
char buffer[RCVBUFSIZE];
int totalrecvsize= 0;
int recvsize= 0;
while(true) {
if(totalrecvsize >= MINIMALMESSAGESIZE) {
break;
} else if(recvsize= recv(sock, buffer totalrecvsize, sizeof(buffer)-totalrecvsize, 0) < 1) {
break;
} else {
totalrecvsize = recvsize;
}
}
Комментарии:
1. Ах да, я забыл » =» при расшифровке из моего источника, теперь он есть в моем первоначальном вопросе. Я не уверен, как определить минимальный размер сообщения, поскольку я могу это выяснить, только проанализировав поле длины. Это означало бы дополнительный вызов recv, которого я бы предпочел избежать.
2. Хорошо, просто прочитайте вашу правку. Дело в том, что в настоящее время я передаю только один буфер протокола, который имеет размер около 10 байт. При развертывании все от одного до 1000 из них должны быть переданы, и я хотел бы получить как можно больше из них как можно быстрее из сети.
3. @dinyar: не забудьте добавить общий полученный размер в буфер при вызове
recv
, иначе вы перезапишете то, что уже получили. Кроме того, если вы не знаете размер сообщения, вы можете вечно ждать вызоваrecv
, если, конечно, сокет не блокируется, и в этом случае будет возвращена ошибка.4. Да, я делаю это,
recvsize = recv
я думаю. Я рассмотрю возможность сделать сокет неблокирующим, спасибо за совет!5. @dinyar: Теперь я видел ваш второй комментарий. В этом случае вам нужно только позаботиться о том, чтобы не перезаписывать ваш буфер в цикле приема.
![]()