URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 8932
[ Назад ]

Исходное сообщение
"Непонятное поведение программы с Интернет-сокетом"

Отправлено AlterFritz , 21-Ноя-10 16:11 
Ниже приведена программа простейшего Web-сервера, из которого выброшено всё, что не относится к проблеме.
А проблема состоит в том, что браузер не получает ответа на запрос. Ответ формируется операторами, обозначенными в нижеследующем коде (функция process_request) как "проблемная группа".
Telnet при этом ответ получает.
Если не читать запроса или поставть операторы проблемной группы перед чтением запроса - браузер получает ответ.
В чём дело?
Проблему я решил, прочитав запрос в предке до fork, а не в потомке, как это делается в программе ниже. Но всё равно непонятно.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netdb.h>
#include <time.h>
int make_server_socket()
{
        struct sockaddr_in saddr;
        int sock_id=sock_id = socket(AF_INET,SOCK_STREAM,0);
        bzero((void*)&saddr,sizeof(saddr));
        if(INADDR_ANY) // проверка для тех систем, где эта константа не ноль
        saddr.sin_addr.s_addr = htonl(INADDR_ANY); // обработка вне зав-ти от номера смаого сервера
        saddr.sin_port = htons(12345);
        saddr.sin_family = AF_INET;
        if(bind(sock_id,(struct sockaddr*)&saddr,sizeof(saddr)) != 0) return -1;
        if(listen(sock_id,1) !=0) return -1;
        return sock_id;
}
void process_request(int fd)
{
        FILE*fp=fdopen(fd,"r+");
        char request[BUFSIZ+1];
        fgets(request,BUFSIZ,fp);
/*------------ проблемная группа --------------------*/
        fprintf(fp, "HTTP/1.0  Error\r\n");
        fprintf(fp, "Content-Type: text/html\r\n");
        fprintf(fp, "Connection: close\r\n\r\n");
        fprintf(fp, "404 ERROR\r\n");
        fclose(fp);
}
int main(int argc,char *argv[])
{
        int sock,fd;
        sock =  make_server_socket();
        while(1) {
                fd = accept(sock,NULL,NULL);
                if(fork()==0) {
                        process_request(fd);
                        exit(0);
                }
                close(fd);
        }
        close(sock);
}

Содержание

Сообщения в этом обсуждении
"Непонятное поведение программы с Интернет-сокетом"
Отправлено guest , 21-Ноя-10 17:14 
> /*------------ проблемная группа --------------------*/
>         fprintf(fp, "HTTP/1.0  Error\r\n");

Попробуйте отдавать нормальных HTTP заголовок.
fprintf(fp, "HTTP/1.0  404\r\n");


"Непонятное поведение программы с Интернет-сокетом"
Отправлено AlterFritz , 21-Ноя-10 18:31 
>> /*------------ проблемная группа --------------------*/
>>         fprintf(fp, "HTTP/1.0  Error\r\n");
> Попробуйте отдавать нормальных HTTP заголовок.
> fprintf(fp, "HTTP/1.0  404\r\n");

Нет, проблема не в этом. Ведь если передать этот неправильный заголовок и всё остальное ДО fgets - всё будет нормально - браузер выдаст страницу. Похоже, здесь какие то тонкости работы с потоками у потомков. Использование read и write не приводит к проблемам!


"Непонятное поведение программы с Интернет-сокетом"
Отправлено guest , 21-Ноя-10 19:05 
а у меня ваш пример (правил только инклюды под систему) и так работает.
Попробуйте так:
fflush(fp);
fclose(fp);
close(fd);

"Непонятное поведение программы с Интернет-сокетом"
Отправлено AlterFritz , 21-Ноя-10 19:28 
> а у меня ваш пример (правил только инклюды под систему) и так
> работает.
> Попробуйте так:
> fflush(fp);
> fclose(fp);
> close(fd);

Попробовал. Увы. И, вроде, последний close не нужен, так как есть fclose. Но всё одинаково. Конечно, можно было бы грешить на браузер, но не работают оба: Firefox и Opera. И опять же telnet-то получает ответ.


"Непонятное поведение программы с Интернет-сокетом"
Отправлено AlterFritz , 21-Ноя-10 19:39 
Тот же результат на почти другой ОС: Fedora 8 и Fedora 14.

"Непонятное поведение программы с Интернет-сокетом"
Отправлено Аноним , 21-Ноя-10 20:14 
Попробуйте использовать анализатор пакетов wireshark, чтобы посмотреть что реально передается по сети...

> Тот же результат на почти другой ОС: Fedora 8 и Fedora 14.


"Непонятное поведение программы с Интернет-сокетом"
Отправлено AlterFritz , 21-Ноя-10 21:17 
> Попробуйте использовать анализатор пакетов wireshark, чтобы посмотреть что реально передается
> по сети...
>> Тот же результат на почти другой ОС: Fedora 8 и Fedora 14.

Попробовал, хотя я в этом не сильно понимаю. Результат такой.
При "нормальной" работе идёт 8 пакетов
1. SYN
2. SYN
3. ACK
4. GET /file HTTP/1.1
5. ACK
6. HTTP/1.0 Error
7. ACK
8. RST

При втором "нормальном" запуске получается 16 пакетов
1. SYN
2. SYN
3. ACK
4. HTTP/1.0 Error
5. ACK
6. FIN
7. GET /file HTTP/1.1
8. RST
9. SYN
10. SYN
11. ACK
12. HTTP/1.0 Error
13. ACK
14. FIN
15. GET /favicon.ico HTTP/1.1
16. RST

Третий запуск аналогичен первому

При "ненормальной" работе тоже сначала 8 пакетов
1. SYN
2. SYN
3. ACK
4. GET /file HTTP/1.1
5. ACK
6. FIN
7. FIN
8. ACK

Потом вываливается сразу 42 пакета, среди которых 5 подряд запросов GET, и также без пакета HTTP/1.0 Error.
Такая картина почти всегда: я всегда видел создание 5 подряд потомков с одним и тем же запросом. Я объяснял это тем, что браузер пытается получить ответ перепосылая запрос.

Другая картина - при работе с read-write
Первый запрос дал 16 пакетов

1. SYN
2. SYN
3. ACK
4. GET /file HTTP/1.1
5. ACK
6. HTTP/1.0 Error
7. ACK
8. Continuation or on-HTTP Traffic
9. ACK
10. Continuation or on-HTTP Traffic
11. ACK
12. Continuation or on-HTTP Traffic
13. ACK
14. FIN
15. FIN
16. ACK

Как это понимать? Буду вспоминать ТСР.


"Непонятное поведение программы с Интернет-сокетом"
Отправлено AlterFritz , 22-Ноя-10 00:18 
> Попробуйте использовать анализатор пакетов wireshark, чтобы посмотреть что реально передается
> по сети...
>> Тот же результат на почти другой ОС: Fedora 8 и Fedora 14.

Проблема, видимо, проста
Надо считывать запрос до конца, а у меня только один fgets торчит.
С telnet-ом запрос считывался за один раз. Wireshark все таки помог.


"Непонятное поведение программы с Интернет-сокетом"
Отправлено meantraitor , 21-Ноя-10 20:48 
> Нет, проблема не в этом. Ведь если передать этот неправильный заголовок и
> всё остальное ДО fgets - всё будет нормально - браузер выдаст
> страницу. Похоже, здесь какие то тонкости работы с потоками у потомков.
> Использование read и write не приводит к проблемам!

А чем отличается fread от read, помните?


"Непонятное поведение программы с Интернет-сокетом"
Отправлено AlterFritz , 21-Ноя-10 21:22 
>> Нет, проблема не в этом. Ведь если передать этот неправильный заголовок и
>> всё остальное ДО fgets - всё будет нормально - браузер выдаст
>> страницу. Похоже, здесь какие то тонкости работы с потоками у потомков.
>> Использование read и write не приводит к проблемам!
> А чем отличается fread от read, помните?

Буферизованный ввод-вывод. Но fread я не пробовал. Прекрасно работает и с fgets, если его сделать в предке, а в потомке уже писать в стандартный вывод. Проблема возникает если fgets выполнять в потомке. А read тоже работает как то мне непонятно, судя по картине пакетов.