Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

send() + recv() on nonblocking tcp sockets

by ph713 (Pilgrim)
on Oct 12, 2005 at 16:32 UTC ( [id://499584]=perlquestion: print w/replies, xml ) Need Help??

ph713 has asked for the wisdom of the Perl Monks concerning the following question:

Once again, I'm turning to the monks in hopes that somebody has sorted this mess out before. I have a class (let's call it Acme::Connection) which handles tcp connections and abstracts them a bit. The question at the heart of this node is: What is the correct way to code for tcp sending and receiving in perl such that you handle all possible error conditions correctly, quickly, and efficiently, with gauranteed maximum timeouts of varying amounts throughout? (A maximum timeout for connecting, for recv()ing the first packet, perhaps a longer timeout for recv()ing the next packet, etc)...

And what that question really boils down to is - for a nonblocking tcp connection, what is the correct way to handle all the possible outcomes of calling $socket->recv($numbytes);.

There's the actual return value we can check for defined-ness, there's the definedness and/or length of the received data versus the $numbytes we asked for, and there's several different relevant errnos which require different sorts of action. it ends up being a matrix of many possibilities and few documented gaurantees... In the case of send() the possibilities are even more complex, but in practice it tends to never fail for reasonably-sized packets on an open connection.

Specifically, the expected behavior is that one can open a connection with:
my $conn = Acme::Connection->new({ ip_addr => '1.2.3.4', port => 666, def_timeout => 12 });
And that one can send or receive a chunk of data with the following calls:
my $data = $conn->recv(3124); $conn->send($data);

The expected behavior is that $conn->recv(3124) will attempt to receive 3124 bytes of data over the network, and will fail with a timeout exception if that doesn't occur within 12 seconds (set with def_timeout in the constructor).

Similarly, $conn->send($data) should send the contents of $data, and fail with a timeout exception if that doesn't happen in 12 seconds.

I've truncated what used to be here, it was a big peice of ugly code, the current implementation at the time of the question.

Replies are listed 'Best First'.
Re: send() + recv() on nonblocking tcp sockets
by salvix (Pilgrim) on Oct 13, 2005 at 21:05 UTC
    It seems that your code is doing what you want now, so I'm not sure what your question is.

    You may want to look at a TCP server with IO::Select from the POE website and also read these 4 excellent examples on how to use POE. It's going to save you a lot of the standard network I/O headaches and you will have only to implement the buffering code to return only when you've read $data_length bytes. The last example is the way to go! :)

      I'm not entirely sure what my question should be at this point either. In any case I've moved on past this specific problem and into other related things now.

      POE doesn't cut it though, and neither do some of the other tcp server modules I've tried out on this problem, like Net::Server::*. The project this is a part of has pretty hardcore requirements that don't fit the mold. The server end of this project would have better off done in C in many ways (even better, implemented as an apache module in C (: ), but perl is far more convenient for other aspects of the project, and in the end perl wins for this thing.

      I just need to sort out a preforking tcp server, client network code, and an underlying protocol abstraction for both, that performs well enough under my requirements and handles all of the potential error conditions correctly and efficiently. What I ended up doing to get it right, was I basically parsed through Apache 2.1.x's code for all of the above, sorted it out from all the abstracted ap_/apr_ library calls as to what exactly it was doing in terms of libc and system calls, and started translating that into perl. It's going pretty well so far, and doing much better than my earlier implementations including the one that's updated in the node above.

      Someday when (if??) I ever finish this project which has spawned most my various questions over the past several months, I think I'll have to make writeup about it (without of course giving away the project, it is private inhouse commercial software after all). While I often seem frustrated with perl when I post here, that's just because I only post here when I'm frustrated. Perl (and PostgreSQL too) has far exceeded what I would have expected from it before I started this project.

      You'd be amazed the scale and complexity and reliability you can ultimately get out of a Perl-based architecture. In testing I'm churning hundreds of gigabytes in a PostgreSQL database, all network-driven by ~3500+ distinct client machines and hitting the database at a rate of somewhere in the neighborhood of ~200 database write transactions per second, 24/7 with no lulls in activity allowed.

      Actually I think I'm going to truncate most of the toplevel node here, as it's pretty useless now, and was always unintelligible :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://499584]
Approved by monkfan
Front-paged by tye
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (8)
As of 2024-04-19 12:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found