Forum Moderators: coopster & phranque

Message Too Old, No Replies

Connection: Close

close(STDOUT)

         

blakmonk

9:07 pm on Jun 3, 2004 (gmt 0)

10+ Year Member



Hi,

I'm trying to implement a little cheat in my code. I want the send some information to the calling application, then tell him to close, then cary on the script doing stuff. That way the app that calls my script thinks it went faster then it really is.

I'm using the Connection: Close trick.

in my perl script I write:

Content-Type: Text/html
Connection: close
Content-Length: 5

22222

this works perfectly if the caller application is a webbrowser that understands Connection: Close it works great. But with an application that does not... well It waits for the script to end.

I tried using close(STDOUT). It works, but the scripts dies shortly after the close statement and does not complete.

How do I do this?

Basicaly, the question is, how do I close STDOUT without killing my process?

BlakMonk

VectorJ

2:22 am on Jun 4, 2004 (gmt 0)

10+ Year Member



The only thing I can think of is to fork a new process and close the parent process. Have you tried sniffing the packets from a normally terminating CGI to see what it sends to the browser/calling process? Seemed to work out well for you last time, maybe that's all you need; to send the normal "close connection" TCP/IP response.

blakmonk

3:32 pm on Jun 4, 2004 (gmt 0)

10+ Year Member



Hi VectorJ,

Well, this is one case sniffing won't help.

See, the Connection: Close is defined in the RFC that defines the HTTP protocol. So browsers have to support it. It helps speed web sessions. The browser does not have to wait for the socket to be closed, it simply reads the number of characters specified by Content-Lenth then closes the connection.

I cannot modify the calling applications, I can only modify my application. Since it's cgi/perl and not mod_perl It (the script) doesn't can't really talk to the httpd (not that I know of).

Closing the STDOUT is the only think I can think of. But when I close STDOUT, the parent process (HTTPD) thinks the child is done, then cleans up after itself, thus killing the script. Which is perfectly logical.

I don't know how to bypass that yet.

BlakMonk

VectorJ

6:59 pm on Jun 4, 2004 (gmt 0)

10+ Year Member



How about splitting the extra stuff that needs to be done after the browser session is closed into another script and using exec() from the cgi to execute the extra code. exec() terminates the current process for you and doesn't return, so it would look like the cgi finished executing to any http client (as well as to httpd).

(wish I could answer your original question about how to close STDOUT, but nothing comes to mind; that's why I'm trying to think of alternatives)

blakmonk

7:44 pm on Jun 4, 2004 (gmt 0)

10+ Year Member



Hi,

I really appreciate the time you take.

Well, sending the rest of the treatemetn to a child process is not really an option. I would have to restart the entire process from scratch. The function I want to cheat on is a bunch of inserts into a database.

I even tried to re-open STDOUT, but it's too late, once it's closed httpd starts the cleaning process.

blakmonk

VectorJ

3:18 am on Jun 5, 2004 (gmt 0)

10+ Year Member



The only other thing I can think of is pretty much overkill: creating a daemon that will handle the mysql queries/updates for the cgi. If you get the chance, update us all on what your solution turned out to be....

kaled

10:40 am on Jun 5, 2004 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I'm new to perl, cgi, http headers, etc. so what I'm about to suggest may be complete garbage.

Why not redirect the user to another page with a Location: ....?

Perhaps this forces the script to close, perhaps the redirection does not take place until the script closes - I don't know.

Perhaps do the same by using a META redirect.

Alternatively, run the script from a small on-click popup or something like that and close the window when it's done. Credit-card clearing companies sometimes do something like this.

Kaled.

SeanW

6:46 pm on Jun 5, 2004 (gmt 0)

10+ Year Member




exec() terminates the current process for you and doesn't return

The exec() system calls *replace* the current process, not terminate it (behind the scenes, every time you fire off a new process, it's a fork() then an exec())

[perl]
[root@bob root]# cat foo1.c
#include <stdio.h>

void main(void) {
printf("In foo1, pid= %d\n", getpid());
}

[root@bob root]# cat foo2.c
#include <stdio.h>

void main(void) {

printf("In foo2, pid= %d\n", getpid());
printf("execing!\n");
execv("foo1", NULL);
}
[/perl]

[root@bob root]# ./foo2
In foo2, pid= 24300
execing!
In foo1, pid= 24300

VectorJ

10:09 pm on Jun 5, 2004 (gmt 0)

10+ Year Member



SeanW is totally right. Thanks for clearing that up!

SeanW

10:41 pm on Jun 5, 2004 (gmt 0)

10+ Year Member



I think your best bet is to fork() a worker process, or some sort of RPC (SOAP, etc) to a daemon that's sitting around waiting for it.

The first is pretty easy...

[perl]
if (fork()) {
# parent process
# send out the message here to close the connection
} {
# child process
# do the dirty work
}
[/perl]

Sean

blakmonk

3:12 pm on Jun 8, 2004 (gmt 0)

10+ Year Member



Hi guys,

Thank you all for your replies, let me try to replie back in order:

VectorJ:
The daemon to handle the queries is really over kill, since it's not just queries, there is lots of treatment done on the data that is returned by the DB.

Kaled:
You maybe new, but you have good ideas... but! my problem comes from the fact that the client that is reading the response from the web server does not understand the HTTP language. It's a socket application that sends the HTTP request then reads the response blindly.

SeanW:
I understand exec, wil would be great if the work was being done but a sub-process, but it has to be done by the current process. It I could have such a thing as a Self->Exec, something that would fork the running process itself and continue it from where it is crrently... httpd work think that the process would have died. and woulnd try to kill it's children.

SeanW:
Would the fork continue the current process?

BlakMonk

SeanW

6:43 pm on Jun 8, 2004 (gmt 0)

10+ Year Member



Would the fork continue the current process?

fork() returns twice, once in the parent process, once in the newly created child process. The return value of the call tells you which one you're in (see the comments in the code snippets I posted)

Sean

blakmonk

8:23 pm on Jun 8, 2004 (gmt 0)

10+ Year Member



Does it continue from where it is at or from the beginning of the code? are the variables transfered on to the child?

And what parent dies, does it take the child with him?

BlakMonk

SeanW

8:41 pm on Jun 8, 2004 (gmt 0)

10+ Year Member




Does it continue from where it is at or from the beginning of the code?

Right after the fork(). That's why it's usually wrapped in the if statement I showed you, ie to determine if you returned in the parent process (in which case fork() returns the child's pid), or if you're in the child process (in which case fork() returns 0)


are the variables transfered on to the child?

Yes, including file descriptors. You may want to close STDIN/STDOUT when in the child process.


And what parent dies, does it take the child with him?

No, init (pid 1) takes on the child process.

I wrote an article about this a while back that might clear it up:

[ertw.com...]

Sean

blakmonk

4:00 pm on Jun 14, 2004 (gmt 0)

10+ Year Member



Sorry for the delay, been cauth in some emergency.

I'll read your article. and test forking...

It looks exactly like what the doctor ordered.

thank you for your time.

Frantzcy