LINUX.ORG.RU

[CGI] Определить разрыв соединения

 


0

0

Как из CGI можно определить, что соединение разорвано, и данные отправляются по сути в /dev/null, а не в клиентский браузер? Поиск никаких результатов не дал. А вводить таймаут работы скрипта я не могу: его могут запустить и на пару минут, и на пару суток... Делать небольшой таймаут и reload тоже не очень хорошо: при перезагрузке будет хорошо заметна задержка.

☆☆☆☆☆

Если у тебя разрывы раз в сутки, то звони в сапорт провайдера =)

По сабжу - реализовать что-нибудь типа пинга адреса, с которого коннектились?

Zhbert ★★★★★
()

>данные отправляются по сути в /dev/null

Они не отправляются в девнул. Программа повиснет при попытке в очередной раз отослать буфер.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Ничего она не виснет. Работает себе дальше (по логам видно).

А про разрывы поясню. Я имел в виду вот что: клиент открывает веб-страницу, с нее запускается CGI и шлет клиенту поток данных (непрерывно), клиент закрывает окно (т.е. обрывает соединение со своей стороны), а CGI продолжает работать. Веб-сокеты еще, к сожалению, не поддерживаются всеми нормальными браузерами, поэтому ими воспользоваться нельзя.

Как можно определить, что клиенту уже не нужен этот CGI, чтобы отключить скрипт?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Научить сервер мочить скрипт, если не удаётся ничего записать в сокет.

Надо отметить, что сейчас всё делается наоборот, даже всякие ngnix'ы изобретают, лишь бы тормоза сети не мешали скрипту.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

Научить сервер мочить скрипт

И как апач этому научить?

Eddy_Em ☆☆☆☆☆
() автор топика

Ну в PHP это реализовано так:

static int sapi_cgibin_ub_write(const char *str, uint str_length TSRMLS_DC)
{
        const char *ptr = str;
        uint remaining = str_length;
        size_t ret;

        while (remaining > 0) {
                ret = sapi_cgibin_single_write(ptr, remaining TSRMLS_CC);
                if (!ret) {
                        php_handle_aborted_connection();
                        return str_length - remaining;
                }
                ptr += ret;
                remaining -= ret;
        }

        return str_length;
}

Идея в том, что если write(2) в STDOUT возвращает отрицательный результат, это говорит о разорванном соединении.

sjinks ★★★
()
Ответ на: комментарий от sjinks

Идея в том, что если write(2) в STDOUT возвращает отрицательный результат, это говорит о разорванном соединении.

Проверил:

#include <stdio.h>
#include <unistd.h>
#include <string.h>

main(){
	int i, j;
	char *str = "Проверка связи\n";
	FILE *f = fopen("tmp", "w");
	setbuf(f, NULL);
	j = strlen(str);
	do{
		i = printf(str);
		fprintf(f, "i=%d\n", i);
		sleep(1);
	}while(i == j);
}
- ничего подобного! Как писалось в файл tmp i=15 при рабочем соединении, так и после разрыва пишется 15.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Попробовал с write и отловом сигналов:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

FILE *f;
void sighandler(int sig){
	fprintf(f, "signal: %d\n", sig);
	fprintf(stderr, "sig: %d\n", sig);
}

main(){
	int i, j, _;
	char *str = "Проверка связи\n";
	f = fopen("tmp", "w");
	setbuf(f, NULL);
	for(_=0; _<256; _++) signal(_, sighandler);
	j = strlen(str);
	do{
		i = write(1, str, j);
		fprintf(f, "i=%d\n", i);
		sleep(1);
	}while(i == j);
}
Все равно пишет i=15, и никаких сигналов...

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от sjinks

Не работает, ни со sleep, ни без него. Без него вообще поток данных такой бешеный идет, что httpd буквально за полминуты отожрал 1.5Гб оперативки и его пришлось прихлопнуть.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Такой код, все работает:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

int main(int argc, char** argv)
{
        signal(SIGPIPE, SIG_IGN);
        int i, j;
        FILE* f = fopen("/tmp/log", "w");
        char* str = "Проверка связи\n";
        char* hdr = "Status: 200 OK\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n";

        setbuf(f, NULL);
        setbuf(stdout, NULL);

        j = strlen(str);
        fprintf(stdout, "%s", hdr);

        do {
                i = fprintf(stdout, str);
                fprintf(f, "i=%d\n", i);
                usleep(1000);
        } while (i == j);

        fprintf(f, "%s\n", "Connection closed.");
        fclose(f);
        return 0;
}

А память httpd поел потому что нужно было заголовки сначала отправить.

sjinks ★★★
()
Ответ на: комментарий от sjinks

Спасибо!

Только ваш код не писал сообщение «Connection closed.», потому что получал SIGTERM. Я переделал:

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 

FILE* f;
void sighandler(int sig){ 
   fprintf(f, "signal: %d\n", sig); 
   fprintf(f, "Connection closed.\n"); 
} 

int main(int argc, char** argv) 
{ 
        signal(SIGPIPE, sighandler); 
        signal(SIGTERM, sighandler);
        int i, j; 
        f = fopen("/tmp/log", "w"); 
        char* str = "Проверка связи\n"; 
        char* hdr = "Content-Type: text/plain; charset=koi8-r\n\n"; 
        setbuf(f, NULL); 
        setbuf(stdout, NULL); 
 
        j = strlen(str); 
        fprintf(stdout, "%s", hdr); 
 
        do { 
                i = fprintf(stdout, str); 
                fprintf(f, "i=%d\n", i); 
                sleep(1); 
        } while (i == j); 
        return 0; 
}
Теперь при обрыве соединения в лог пишется
signal: 15
Connection closed.
signal: 13
Connection closed.
i=-1
Получается, при отправке правильных заголовков все работает (и SIGTERM отсылается, и printf возвращает -1, и отсылается SIGPIPE при попытке записи), а без заголовка - нет.

Eddy_Em ☆☆☆☆☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.