Вопрос или проблема
Я новичок в написании bash-скриптов и в данный момент в основном использую chatgpt для создания шаблонов. Я пытаюсь создать простой HTTP-сервер на базе netcat, который будет принимать и хранить .png файлы. У меня есть второй скрипт, предназначенный для тестирования этого, и сейчас он выдает ошибку broken pipe. Я не совсем понимаю, что это значит в этом контексте, так как на самом деле я не передаю данные по сети. Буду признателен за любые подсказки. Я не нов в программировании, но нов в bash/сетях/web-разработке.
Вывод терминала тестового скрипта:
Отправка PUT-запроса на http://127.0.0.1:1881...
* Пробую 127.0.0.1:1881...
% Всего % Получено % Отправлено Средняя скорость Время Время Время Текущая
Загрузка Загрузка Всего Израсходовано Осталось Скорость
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Подключено к 127.0.0.1 (127.0.0.1) порт 1881 (#0)
PUT /test_image.png HTTP/1.1
Host: 127.0.0.1:1881
User-Agent: curl/7.81.0
Accept: */*
Content-Length: 16074
Expect: 100-continue
* Отметить пакет как несовместимый с многоразовым использованием
HTTP/1.1 100-continue
* Ошибка отправки: Broken pipe
0 16074 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
* Закрытие соединения 0
curl: (55) Ошибка отправки: Broken pipe
Тестовый скрипт:
#!/bin/bash
# Определите адрес сервера и порт
SERVER_ADDRESS="127.0.0.1"
SERVER_PORT=1881
# Файл для отправки
TEST_FILE="test_image.png"
# Проверьте, существует ли тестовый файл
if [[ ! -f "$TEST_FILE" ]]; then
echo "Тестовый файл '$TEST_FILE' не существует. Создание временного файла..."
echo "Это тестовый файл." > "$TEST_FILE"
fi
# Используйте curl для отправки PUT-запроса с опцией --upload-file
echo "Отправка PUT-запроса на http://$SERVER_ADDRESS:$SERVER_PORT..."
RESPONSE=$(curl -v http://$SERVER_ADDRESS:$SERVER_PORT --upload-file $TEST_FILE)
# Проверьте код HTTP-ответа
if [[ "$RESPONSE" == "200" ]]; then
echo "PUT-запрос выполнен успешно. Сервер вернул HTTP 200 OK."
else
echo "PUT-запрос не удался. Сервер вернул HTTP $RESPONSE."
fi
Скрипт сервера:
#!/bin/bash
# Определите IP-адрес и порт для HTTP-сервера
IP_ADDRESS="127.0.0.1"
PORT=1881
# Каталог для хранения полученных данных
UPLOAD_DIR="Data"
# Запустите HTTP-сервер с помощью netcat
echo "Запуск HTTP-сервера на $IP_ADDRESS:$PORT..."
while :
do
echo -e "HTTP/1.1 100-continue \r\n" | nc -l -s $IP_ADDRESS -p $PORT -q 1 > request.txt
# Сгенерируйте имя файла на основе временной метки
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
OUTPUT_FILE_PATH="$UPLOAD_DIR/received_$TIMESTAMP.png"
# Сохраните полученные данные в определенный путь вывода
sed -n '/\r\n\r\n/{n;p;}' request.txt > "$OUTPUT_FILE_PATH"
echo "Полученные данные PUT сохранены в $OUTPUT_FILE_PATH"
done
Ответ или решение
Ошибка "Broken pipe" (система прервала соединение) при работе с curl и netcat может возникать по нескольким причинам. Ниже я представлю детальный анализ указанных вами скриптов и предложу, как решить эту проблему.
1. Понимание проблемы "Broken pipe"
Ошибка "Broken pipe" указывает на то, что одно из соединений прервало связь, пока другое соединение всё ещё пыталось передать данные. В вашем случае, это означает, что эталонный скрипт, отправляющий данные с помощью curl
, пытается отправить данные на сервер через netcat
, который, возможно, закрыл соединение до того, как все данные были отправлены.
2. Анализ скриптов
Скрипт клиента
#!/bin/bash
# Определяем адрес сервера и порт
SERVER_ADDRESS="127.0.0.1"
SERVER_PORT=1881
# Файл для отправки
TEST_FILE="test_image.png"
# Проверяем, существует ли тестовый файл
if [[ ! -f "$TEST_FILE" ]]; then
echo "Тестовый файл '$TEST_FILE' не существует. Создаем его..."
echo "This is a test file." > "$TEST_FILE"
fi
# Используем curl для отправки PUT запроса
echo "Отправка PUT запроса на http://$SERVER_ADDRESS:$SERVER_PORT..."
RESPONSE=$(curl -v --upload-file "$TEST_FILE" http://$SERVER_ADDRESS:$SERVER_PORT)
# Проверяем HTTP код ответа
if [[ "$RESPONSE" == *"200 OK"* ]]; then
echo "PUT запрос успешно выполнен. Сервер вернул HTTP 200 OK."
else
echo "PUT запрос завершился неудачно. Сервер вернул HTTP $RESPONSE."
fi
Скрипт сервера
#!/bin/bash
# Определяем IP адрес и порт для HTTP сервера
IP_ADDRESS="127.0.0.1"
PORT=1881
# Директория для хранения полученных данных
UPLOAD_DIR="Data"
# Запускаем HTTP сервер с помощью netcat
echo "Запуск HTTP сервера на $IP_ADDRESS:$PORT..."
mkdir -p "$UPLOAD_DIR"
while :; do
echo -e "HTTP/1.1 100-continue\r\n" | nc -l -s $IP_ADDRESS -p $PORT -q 1 > request.txt
# Генерируем имя файла на основе текущей метки времени
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
OUTPUT_FILE_PATH="$UPLOAD_DIR/received_$TIMESTAMP.png"
# Сохраняем полученные данные в файл
sed -n '/\r\n\r\n/{n;p;}' request.txt > "$OUTPUT_FILE_PATH"
echo "Полученные данные сохранены в $OUTPUT_FILE_PATH"
done
3. Возможные источники проблемы
-
Проблема с ответом от сервера: Когда клиентское приложение обращается к серверу с запросом
PUT
, сервер должен быть готов принять данные. В вашем случае сервер отправляет ответ "HTTP/1.1 100-continue" и сразу же прекращает ожидать. Это может вызвать ошибки на стороне клиента, так как клиент может интерпретировать это как закрытие соединения до начала передачи данных. -
Генерация имен файлов: Директория для сохранения файлов может не существовать, в результате чего в попытке сохранить файл возникнет ошибка.
4. Решения
Изменение сервера
-
Убедитесь, что директория для хранения файлов существует:
mkdir -p "$UPLOAD_DIR"
-
После отправки 100-continue сервер должен быть готов получить данные. Измените логику вашего сервера на следующее:
while :; do
# Чтение запроса с помощью nc
{ echo -e "HTTP/1.1 200 OK\r\n"; cat; } | nc -l -s $IP_ADDRESS -p $PORT -q 1 > request.txt
# Генерируем имя файла на основе текущей метки времени
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
OUTPUT_FILE_PATH="$UPLOAD_DIR/received_$TIMESTAMP.png"
# Сохраняем полученные данные в файл
sed -n '/\r\n\r\n/{n;p;}' request.txt > "$OUTPUT_FILE_PATH"
echo "Полученные данные сохранены в $OUTPUT_FILE_PATH"
done
- Убедитесь, что всё настраивается правильно. Сервер должен корректно обрабатывать данные от клиента и подтверждать успешный прием файлов.
Заключение
Обратите внимание на то, как сервер обрабатывает запросы и статусные коды. Убедитесь, что вы корректно открываете, принимаете и закрываете соединения. После внесения указанных изменений тестовый сценарий с использованием curl
должен пройти успешно без ошибок "Broken pipe".