tonyk_av 43 8 мая, 2023 Опубликовано 8 мая, 2023 · Жалоба Всем привет! Пишу минимальный сервер. Использую STM32F407+W5500, Filezilla. После получения команды LIST, открываю второе соединение, дожидаюсь подключения к нему клиента, которому отправляю список файлов. Но клиент висит на ожидании получения списка файлов. Прочитал RFC959, но ответа там не вижу. Клиент ошибок не выдаёт. Что я не учёл? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 49 8 мая, 2023 Опубликовано 8 мая, 2023 (изменено) · Жалоба 20 минут назад, tonyk_av сказал: Но клиент висит на ожидании получения списка файлов. Ну так поднимите сервер на компе и проверьте на заведомо рабочем, если заработает, смотрите шарком, что не так делаете... Можно еще попробовать в качестве клиента тотал коммандер, я им проверял свой сервер. Изменено 8 мая, 2023 пользователем mantech Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Ruslan1 17 8 мая, 2023 Опубликовано 8 мая, 2023 · Жалоба По названию темы у Вас FTP сервер не видит передаваемых ему данных. А в тексте говорите что клиент не видит данных. ??? там вроде никаких премудростей нет. У меня так работает case FTP_CMD_LIST: { if (*dataConnMode == NO_CONNECTION) { FTP_SendReply(conn, FTP_REPLY_503); break; } err = ERR_VAL; if(*dataConnMode == ACTIVE_MODE) { if ((pcb->ConnectIP.addr == 0) || (pcb->ConnectPort == 0)) { FTP_SendReply(conn, FTP_REPLY_503); } data_conn = netconn_new(NETCONN_TCP); netconn_set_recvtimeout(data_conn, 1000 * 60 * 2); //2 min timeout data_conn->pcb.tcp->keep_idle = 5000; data_conn->pcb.tcp->keep_intvl = 1000; data_conn->pcb.tcp->keep_cnt = 5; data_conn->pcb.tcp->so_options |= SOF_KEEPALIVE; err = netconn_connect(data_conn, &pcb->ConnectIP, pcb->ConnectPort); } else { if(*dataConnMode == PASV_MODE_CONNECTED) { err = ERR_OK; data_conn = pasvConn; } } LOG_CONSOLE ("\r\nLIST command for: '%s\n",fullPath); if (err == ERR_OK) { //file_err = f_getcwd(pcb->buff, sizeof(pcb->buff)); snprintf (pcb->buff, FTP_COMMON_BUFF_SIZE, "%s",fullPath); // if (file_err != FR_OK) // { // FTP_SendReply(conn, FTP_REPLY_550); // } // else // { LOG_CONSOLE ("FTPserv: LIST cmd for '%s'\n",pcb->buff); FTP_SendReply(conn, FTP_REPLY_150); FTP_SendList(data_conn, pcb, fullPath); FTP_SendReply(conn, FTP_REPLY_226); // } } else { FTP_SendReply(conn, FTP_REPLY_425); } if(*dataConnMode == PASV_MODE_CONNECTED) { *dataConnMode = PASV_MODE_FINISHED; netconn_close(data_conn); netconn_delete(data_conn); } else { if(*dataConnMode == ACTIVE_MODE) { *dataConnMode = NO_CONNECTION; netconn_close(data_conn); netconn_delete(data_conn); } } break; } /** * \brief FTP_SendList() - Sends the list of files in actual server to open connection * \param *conn - net connection type and status * \param *pcb - FTP connection status and information * \retval None */ void FTP_SendList(struct netconn *conn, ftp_pcb_t *pcb, char* fullPath) { FRESULT file_err; err_t err; DIR fdir; FILINFO fno; uint32_t size; TCHAR *pntName; #define timeStringLEN 30 char timeString[timeStringLEN]; if ((fullPath[0] == '/') && (fullPath[1] == '\0')) // maybe fullPath is "/" {//it's a root directory, show all available disks for (uint8_t n = 0; n < FF_VOLUMES; n++) { size = snprintf(pcb->buff, sizeof(pcb->buff), "%c%s %s %s %s %u %s /%s\r\n", 'd', "rw-------", "1", "user", "group", 0, "Jan 01 2018", VolumeStr[n] ); if (size>=sizeof(pcb->buff)) {// the string length was truncut from nChars to maxLength size = sizeof(pcb->buff)-1; pcb->buff[size] = '\0'; } err = netconn_write(conn, pcb->buff, size, NETCONN_COPY); if (err != ERR_OK) return; } return; } file_err = f_opendir_safe(&fdir, fullPath,F_SAFE_DELAY); if (file_err == FR_OK) { // read all the entries in directory while(1) { file_err = f_readdir(&fdir, &fno); if (file_err != FR_OK || fno.fname[0] == 0) break; // if file starts by . it is the . or .. usual links if (fno.fname[0] == '.') continue; pntName = fno.fname; {//prepare time string struct tm fileTime_tm; time_t fileTime_timet, currTime_timet; double deltaT; double time180DaysInSeconds = 180.0 * 24.0 * 3600.0; //file time fileTime_tm.tm_year = (((fno.fdate >> (25 - 16)) & 0x7F) + 1980) - 1900; fileTime_tm.tm_mon = ((fno.fdate >> (21 - 16)) & 0x0F) - 1; //in struct tm: month is 0 to 11 range, but FAT uses 1 to 12 range fileTime_tm.tm_mday = (fno.fdate >> (16 - 16)) & 0x1F; fileTime_tm.tm_hour = (fno.ftime >> 11) & 0x1F; fileTime_tm.tm_min = (fno.ftime >> 5) & 0x3F; fileTime_tm.tm_sec = ((fno.ftime) & 0x01F) << 1; //2-second count, valid value range 029 inclusive (0 58 seconds). fileTime_timet = mktime(&fileTime_tm); //current time currTime_timet = get_time_seconds(); //difference deltaT = difftime(currTime_timet, fileTime_timet); if (deltaT >= time180DaysInSeconds) { // format for times older than 180 days strftime(timeString,timeStringLEN,"%b %d %Y", &fileTime_tm); } else { //format for time more recent than 180 days strftime(timeString, timeStringLEN, "%b %d %H:%M", &fileTime_tm); } } size = snprintf(pcb->buff, sizeof(pcb->buff), "%c%s %s %s %s %u %s %s\r\n", (fno.fattrib & AM_DIR) ? 'd' : '-', "rw-------", "1", "user", "group", fno.fsize, timeString, pntName ); if (size>=sizeof(pcb->buff)) {// the string length was truncut from nChars to maxLength size = sizeof(pcb->buff)-1; pcb->buff[size] = '\0'; } err = netconn_write(conn, pcb->buff, size, NETCONN_COPY); if (err != ERR_OK) break; } f_closedir(&fdir); } } 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 8 мая, 2023 Опубликовано 8 мая, 2023 · Жалоба 2 hours ago, Ruslan1 said: там вроде никаких премудростей нет. У меня так работает Ruslan1, благодарю! Заработало! Сравнил код выше и свой. Можно сказать, что совпадает один в один, но у себя в коде после сравнения увидел ошибку, состоящую в том, что я из-за неправильного условия устанавливал соединение по каналу передачи данных не по команде PASV, а по LIST. Разница буквально в одну строчку, которая воткнулась мне в глаз и указала на мою ошибку. P. S. Пример написан, по-моему, очень внятно, всё понятно, хотя тут netconn, а у меня класс ввода вывода на базе socket от Wiznet. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 16 мая, 2023 Опубликовано 16 мая, 2023 (изменено) · Жалоба . Изменено 16 мая, 2023 пользователем tonyk_av Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 16 мая, 2023 Опубликовано 16 мая, 2023 (изменено) · Жалоба Не буду плодить темы, спрошу тут. Передача пошла, но Filezilla не правильно интерпретирует ответ на команду LIST. Отправляю с сервера: Клиент отображает: Месяц, число и год слились с именем файла и директории. Что я делаю не так? P. S. Посмотрел пример выше от Ruslan1, но разницы в формате вывода не заметил. Изменено 16 мая, 2023 пользователем tonyk_av Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 18 мая, 2023 Опубликовано 18 мая, 2023 · Жалоба On 5/16/2023 at 8:25 PM, tonyk_av said: Что я делаю не так? Могу предположить, что вы делаете опечатку в названии месяца, и Filezilla не может его распарсить. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 19 мая, 2023 Опубликовано 19 мая, 2023 · Жалоба 13 hours ago, esaulenka said: Могу предположить, что вы делаете опечатку в названии месяца, и Filezilla не может его распарсить. 👍 Хорошая мысль! Проверю. Ну и сам напартачил тоже.😥 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 19 мая, 2023 Опубликовано 19 мая, 2023 · Жалоба On 5/18/2023 at 7:11 PM, esaulenka said: Могу предположить, что вы делаете опечатку в названии месяца, и Filezilla не может его распарсить. Так и оказалось! Благодарю! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 4 августа, 2023 Опубликовано 4 августа, 2023 · Жалоба Всем привет! В процессе тестирования обнаружилось, что при загрузке файла в МК часто теряется последний переданный пакет. В документации не могу найти ответ на вопрос о том, можно ли вызывать disconnect(), если в буфере сокета есть пришедшие, но не прочитанные данные? Пока грешу на это, но возможно, есть другая причина? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 4 августа, 2023 Опубликовано 4 августа, 2023 · Жалоба Вообще в спецификации TCP указано, что данные могут передаваться и в последних пакетах, которые уже с флагом FIN. Так что, даже если вы - сторона инициировавшая разрыв соединения, то уже даже после этого другая сторона может отправить вам данные. Вместо со своим флагом FIN. Так что даже после вызова dissconnect() могут прийти, даже если и не было на момент её вызова. По идее буфер TCP-соединения нужно ещё раз вычитывать уже после полного закрытия сокета. У меня в одном проекте тоже похоже иногда наблюдается подобная проблема. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 4 августа, 2023 Опубликовано 4 августа, 2023 · Жалоба 29 minutes ago, jcxz said: По идее буфер TCP-соединения нужно ещё раз вычитывать уже после полного закрытия сокета. Подляна в том, что при попытке чтения мне возвращается 0. Тут суть вопроса не в теории работы ТСР, хотя за мысль с FIN благодарю, а именно в особенностях работы W5500. Возможно, перед закрытием сокета надо удостоверится в отсутствии данных и не переводить сокет в состояние "Соединение разорвано". Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 4 августа, 2023 Опубликовано 4 августа, 2023 · Жалоба 27 минут назад, tonyk_av сказал: Возможно, перед закрытием сокета надо удостоверится в отсутствии данных и не переводить сокет в состояние "Соединение разорвано". Ну так ведь данные могут прийти уже после закрытия сокета. Уже не говоря о том, что они могут прийти между тем как вы удостоверитесь и затем пошлёте команду закрытия. В этом случае только читать буфер после закрытия. 27 минут назад, tonyk_av сказал: Подляна в том, что при попытке чтения мне возвращается 0. А если подождать немного после закрытия и потом прочитать? Я вот у себя подумываю о таком решении в аналогичной ситуации. И ещё вопрос: Закрытие соединения (в этих случаях, когда наблюдается проблема) происходит по чьей инициативе? Вашей или удалённой стороны? У меня такое происходит только когда инициатива разрыва идёт от удалённой стороны. Насколько я заметил. ЗЫ: Я не разбираюсь в API W5500, но мне кажется должен быть какой-то путь получения данных, пришедших во время закрытия TCP-соединения. Так как это - штатная ситуация. Если её не поддерживать, то с некоторыми серверами вообще невозможно будет работать, потому что они всегда присылают данные в составе последнего пакета с FIN. Сомневаюсь, что разработчики W5500 этого не знали и не учли. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 43 4 августа, 2023 Опубликовано 4 августа, 2023 · Жалоба 1 minute ago, jcxz said: Закрытие соединения (в этих случаях, когда наблюдается проблема) происходит по чьей инициативе? Клиента. 11 minutes ago, jcxz said: мне кажется должен быть какой-то путь получения данных, пришедших во время закрытия TCP-соединения Думаю, что мне надо ещё раз почитать даташит и проверить работу конечного автомата у W5500. В паре мест вижу странности в своём коде. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 236 4 августа, 2023 Опубликовано 4 августа, 2023 · Жалоба 1 минуту назад, tonyk_av сказал: Клиента. Получается, что у вас точно та же проблема, что и у меня в проекте. Только у меня не W5500, а ESP8266. 1 минуту назад, tonyk_av сказал: Думаю, что мне надо ещё раз почитать даташит и проверить работу конечного автомата у W5500. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться