Доброго времени суток! Подскажите, что не так. Отправляю на ардуину файл по TCP, соответственно использую EthernetShield для работы. Пишу вот такой код Код (C++): #include <SPI.h> #include <Ethernet.h> #define MAX_BUFFER_SIZE 512 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; EthernetServer server(80); byte ip[] = {10, 0, 0, 174}; void setup() { Serial.begin(9600); Ethernet.begin(mac, ip); server.begin(); Serial.println("server is at "); Serial.println(Ethernet.localIP()); } void loop() { byte filebuffer[MAX_BUFFER_SIZE]; int filesize = 1; EthernetClient client = server.available(); if (client) { while (client.available()) { int t = client.read(filebuffer, MAX_BUFFER_SIZE); delay(100); Serial.println(filesize); Serial.println(t); filesize = filesize + 1; } Serial.println("Write-OK"); Serial.println("getfile-false"); } } Передаю на ардуино файл В мониторе наблюдаю такую картину Код (C++): server is at 10.0.0.174 1 512 2 512 3 512 4 512 5 512 6 512 7 512 8 512 9 512 10 512 11 512 12 512 13 512 14 512 15 512 16 512 17 512 18 512 Write-OK getfile-false 1 512 Write-OK getfile-false 1 512 2 512 3 512 4 276 Write-OK getfile-false ТО есть, как будто while (client.available()) дает отрицательный результат, хотя файл до конца еще не прочитался. Может кто подскажет, что это значит и как с этим бороться?
Ну понятно что ноль, отрицательный для меня. Считаете это нормально и надо код писать с учетом, что на входе может и не быть данных?
В пределах 2кБайт, не более. Сильно большой буфер не нужен в силу того что размер аппаратного буфера в шилде ограничен. На чтение в слишком маленький буфер будет много накладных расходов (вызов функции тоже что-то стоит). Экспериментально можно установить начиная с какого размера рост производительности становится незначительным. Для завершения работы нужно определить признак конца файла. Это может быть символ в самом файле, а может быть завершение сеанса. client.connected() Функция client.available() говорит лишь о том, что в буфере шилда есть непрочитанные данные и их можно прочитать немедленно. Но если данных нет, это не значит, что передача завершена. Нужно подождать когда данные появятся или сеанс завершится.
интересная мысль, надо попробывать. у меня даже блоки по 512 не залезают на флешку (уж не знаю почему), максимум 128. Вопрос на самом деле был больше по стабильности, не будет ли проблем с большим буфером в плане того, что будет искажение информации
В моей практике было, что большие сетевые пакеты не проходили маршрутизатор. Нужно заметить, что read копирует в буфер столько байт, сколько шилд уже принял. Т.е. буфер может быть заполнен не до конца, хотя файл еще не закончился.
ну да, собственно read и возвращает кол-во считанных байт. А вот такая конструкция не работает Код (C++): #include <SPI.h> #include <Ethernet.h> #define MAX_BUFFER_SIZE 512 byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; int filesize = 0; bool startfile = false; EthernetServer server(80); byte ip[] = {10, 0, 0, 174}; void setup() { Serial.begin(9600); Ethernet.begin(mac, ip); server.begin(); Serial.println("server is at "); Serial.println(Ethernet.localIP()); } void loop() { byte filebuffer[MAX_BUFFER_SIZE]; EthernetClient client = server.available(); if (client.connected()==true) { while (client.available()) { startfile=true; int t = client.read(filebuffer, MAX_BUFFER_SIZE); //Serial.println(t); filesize = filesize + t; } } else { if (startfile==true){ Serial.println("Write-OK"); Serial.println(filesize); startfile=false; } } } В мониторе Код (C++): server is at 10.0.0.174 Write-OK 1460 Write-OK 2920 Write-OK 4380 Write-OK 5840 Write-OK 7300 Write-OK 8760 Write-OK 10220 Write-OK 11540 То есть получается соединение тоже сбрасывается, хотя на стороне клиента соединение установлено
Остается опираться на размер файла. Сначала передавать размер, а уже потом файл и сравнивать кол-во считанных байт с размером.
Вы каждый раз нового клиента создаёте после того как буфер опустошился. Вместо Код (C++): if (client.connected()==true) тоже цикл нужен.
не подскажете, как очистить буфер шилда после client.read()? У меня происходит следующая вещь, я посылаю запрос на ардуино, что сейчас буду передавать файл и размер этого файла. Программа переходит на прием файла. Файл принимается, но он битый. В нем в одном месте вместа принятых байт стоят байты из моего последнего запроса Причем стоят они не в хаотичном месте, а в строго определенном, занимают последние 13 байт (это длина моего запроса) в буфере 2048 байт. Если кинуть файл больше 4096 байта, то такая конструкция встретится 2 раза. Такое впечатление, что буфер приема шилда не очищается.
Все одолел. Вот рабочая процедура. Пишет блоками определенного размера Код (C++): void Getfile() { bool errorflag = false; byte filebuffer[MAX_BUFFER_SIZE]; SWITCH_TO_W5100; EthernetClient client = server.available(); if (client) { while (client.available()) { int t = client.read(filebuffer, MAX_BUFFER_SIZE); Serial.print("Client read-"); Serial.println(t); SWITCH_TO_SD; File myFile = SD.open(uploadfilename, FILE_WRITE); if (myFile) { myFile.seek(pos); int t1 = myFile.write(filebuffer, t); delay(20); Serial.print("Write to SD -"); Serial.println(t1); myFile.flush(); myFile.close(); if (t1 != t) { Serial.println("ERROR"); errorflag = true; break; } else { pos = pos + t1; filesize = filesize + t; Serial.println(filesize); SWITCH_TO_W5100; } } } if (filesize == uploadfilesize && errorflag == false) { Serial.println("Write-OK"); pos = 0; filesize = 0; getfile = 0; } else if (errorflag == true) { Serial.println("Write-ERROR"); pos = 0; getfile = 0; filesize = 0; } } }