|
Hi, There is an erlang distribution for Ubuntu, but I'm not sure how new it is (it may be R10). I think it's to be found in the 'universe' - just serch for erlang in synaptic. There is a private newer distribution, but last I checked it was only a Debian package (meaning it would need manual setup). In any case, I didn't have any problem compiling from source on an out-of-the-box Ubuntu 6.06. Good luck! best regards, Vlad _________________________________________________________ Post sent from http://www.trapexit.org _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
I have a question about gen_tcp A client does this: {ok, Port} = gen_tcp:connect(Host, Post, [binary,{packet,N}]) get_tcp:send(Port, <<Bin>>) The server calls gen_tcp:listen(Port, [binary,{packet,N}]) Then goes into a receive loop to receive messages Questions: 1) is <<Bin>> delivered as a single message to the server program? or is the packet fragmented. 2) Does fragmentation or not depend upon N (the packet size) must N be > 0 for the receiver to be able to reconstruct the fragments (if fragmented?) The behaviour appears not to be documented /Joe _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
On 9/14/06, Joe Armstrong (TN/EAB) <[hidden email]> wrote:
> 1) is <<Bin>> delivered as a single message to the server program? > or is the packet fragmented. > 2) Does fragmentation or not depend upon N (the packet size) > must N be > 0 for the receiver to be able to reconstruct the > fragments (if fragmented?) Hi, I think the behaviour isn't documented because it isn't dictated by Erlang, but is dictated by the TCP parameters of the socket. Any TCP packet may be fragmented (it certainly is if it is larger then the current MTU), but I think that even servers along the way (if it's a remote connection) may further fragment it. So to be sure, assume it's fragmented. If N=0 you will have to have your own way to be to reconstruct each message from the TCP stream. Relying on each message to be delivered separately isn't working. I know from personal experience :-) best regards, Vlad _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Joe Armstrong (TN/EAB)
Hi Joe,
I have used this technique with really quite large packets and it always seemed to do the right thing. I typically use {packet, 2} so that the other end cannot fill up my machine with DoS style packets. Sean On 14 Sep 2006, at 12:35, Joe Armstrong ((TN/EAB)) wrote: > > I have a question about gen_tcp > > A client does this: > > {ok, Port} = gen_tcp:connect(Host, Post, [binary,{packet,N}]) > get_tcp:send(Port, <<Bin>>) > > The server > > calls gen_tcp:listen(Port, [binary,{packet,N}]) > > Then goes into a receive loop to receive messages > > Questions: > > 1) is <<Bin>> delivered as a single message to the server > program? > or is the packet fragmented. > > 2) Does fragmentation or not depend upon N (the packet size) > must N be > 0 for the receiver to be able to reconstruct the > fragments (if fragmented?) > > The behaviour appears not to be documented > > /Joe > > > > _______________________________________________ > erlang-questions mailing list > [hidden email] > http://www.erlang.org/mailman/listinfo/erlang-questions _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Joe Armstrong (TN/EAB)
Joe Armstrong (TN/EAB) wrote:
> > I have a question about gen_tcp > > A client does this: > > {ok, Port} = gen_tcp:connect(Host, Post, [binary,{packet,N}]) > get_tcp:send(Port, <<Bin>>) > > The server > > calls gen_tcp:listen(Port, [binary,{packet,N}]) > > Then goes into a receive loop to receive messages > > Questions: > > 1) is <<Bin>> delivered as a single message to the server program? > or is the packet fragmented. I would say that since the tcp_recv call in inet_drv.c is aware of the {packet,N} option set on the socket, gen_tcp:recv(Sock, 0) will (memory permitting) deliver a complete packet of N bytes to the caller. However the packet may get fragmented in the transport layer because of the MTU size excess, though this should be transparent to the caller. > 2) Does fragmentation or not depend upon N (the packet size) > must N be > 0 for the receiver to be able to reconstruct the > fragments (if fragmented?) I think this depends on which socket option is set. For {packet,N} doing gen_tcp:recv(Sock, M), where M != 0 will return an einval (if memory serves) error. If you are using raw socket option, there is a 16M limit on the size of M. You'll get an enomem error in that case. > The behaviour appears not to be documented > > /Joe Regards, Serge _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Sean Hinde
It might well be that it ... "seemed to do the right thing" ... But what I want to knwo is if the gen_tcp layer is *designed* and programmed to only deliver packets of exactly the right length. The fact that your packets are not fragmented might be accidental or by design Is this an accidental propery of do I have to add a layer of code that does the refragmentation - I could read the code, but that would be cheating. Reading the code will tell me what the program actually does, and NOT what it is supposed to do. I guess Tony knows if he's reading this :-) /Joe > -----Original Message----- > From: Sean Hinde [mailto:[hidden email]] > Sent: den 14 september 2006 14:22 > To: Joe Armstrong (TN/EAB) > Cc: [hidden email] > Subject: Re: [erlang-questions] gen_tcp question > > Hi Joe, > > I have used this technique with really quite large packets > and it always seemed to do the right thing. > > I typically use {packet, 2} so that the other end cannot fill > up my machine with DoS style packets. > > Sean > > > On 14 Sep 2006, at 12:35, Joe Armstrong ((TN/EAB)) wrote: > > > > > I have a question about gen_tcp > > > > A client does this: > > > > {ok, Port} = gen_tcp:connect(Host, Post, [binary,{packet,N}]) > > get_tcp:send(Port, <<Bin>>) > > > > The server > > > > calls gen_tcp:listen(Port, [binary,{packet,N}]) > > > > Then goes into a receive loop to receive messages > > > > Questions: > > > > 1) is <<Bin>> delivered as a single message to the server > > program? > > or is the packet fragmented. > > > > 2) Does fragmentation or not depend upon N (the packet size) > > must N be > 0 for the receiver to be able to > reconstruct the > > fragments (if fragmented?) > > > > The behaviour appears not to be documented > > > > /Joe > > > > > > > > _______________________________________________ > > erlang-questions mailing list > > [hidden email] > > http://www.erlang.org/mailman/listinfo/erlang-questions > > _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
On 14 Sep 2006, at 13:33, Joe Armstrong ((TN/EAB)) wrote: > > It might well be that it > > ... "seemed to do the right thing" ... Well, It did the right thing consistently for some years with messages much larger that can be carried in a single LAN packet. Personally I would take that as greater proof than reading it in the documentation. Others of a different persuasion would believe that if it was not written in the documentation then I had in fact created a timebomb guaranteed to fail at the worst possible moment in the future ! Only Ericsson can make any documented guarantees about the default system, not even Tony can provide anything other that a statement of his intent when he wrote it. Sean _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
I'm not interested in what is actually does - I'm interested in what it's supposed to do. The documentation is supposed to tell you what the program is supposed to do and I suppose that it is reasonable to suppose that people are supposed to send error messages if they suppose that the program does not do what might be supposed from the documentation. <I'm almost proud of that sentence> /Joe > -----Original Message----- > From: Sean Hinde [mailto:[hidden email]] > Sent: den 14 september 2006 14:46 > To: Joe Armstrong (TN/EAB) > Cc: [hidden email]; [hidden email] > Subject: Re: [erlang-questions] gen_tcp question > > > On 14 Sep 2006, at 13:33, Joe Armstrong ((TN/EAB)) wrote: > > > > > It might well be that it > > > > ... "seemed to do the right thing" ... > > Well, It did the right thing consistently for some years with > messages much larger that can be carried in a single LAN packet. > Personally I would take that as greater proof than reading it > in the documentation. > > Others of a different persuasion would believe that if it was > not written in the documentation then I had in fact created a > timebomb guaranteed to fail at the worst possible moment in > the future ! > > Only Ericsson can make any documented guarantees about the > default system, not even Tony can provide anything other that > a statement of his intent when he wrote it. > > > Sean > > _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Sean Hinde
On 9/14/06, Sean Hinde <[hidden email]> wrote:
> Well, It did the right thing consistently for some years with > messages much larger that can be carried in a single LAN packet. > Personally I would take that as greater proof than reading it in the > documentation. Then I suppose the problems I had (for some while ago, I think it was R7 or R8) were not caused by this issue or was fixed since. Good to know! regards, Vlad _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Joe Armstrong (TN/EAB)
Joe,
I was not disagreeing with you that it should be documented. I suppose I was making an observation on human (and corporate) behaviour. Personally I am happy to derive an intent from the combination of the existing documentation and my own testing. If it ended up not working as implied by the documentation then I would have had no hesitation to raise a trouble ticket using the commercial support option and blag it. Others are not happy to rely on this level of assumption so it should of course be documented. To the point in hand: I am sure Tony could make some statement of what it was supposed to do when he wrote it, but that is surely not enough. Ericsson might have a plan to change the undocumented behaviour so it only works for packets without an F in the length in an unspecified number base. So, only Ericsson can make any statement of what the program is supposed to do now and in the future. And that place is the documentation and any support contracts you might have with them. BR, Sean On 14 Sep 2006, at 13:53, Joe Armstrong ((TN/EAB)) wrote: > > I'm not interested in what is actually does - > I'm interested in what it's supposed to do. > > The documentation is supposed to tell you what the program is supposed > to do > and I suppose that it is reasonable to suppose that people are > supposed > to > send error messages if they suppose that the program does not > do what might be supposed from the documentation. > > <I'm almost proud of that sentence> > > /Joe > > >> -----Original Message----- >> From: Sean Hinde [mailto:[hidden email]] >> Sent: den 14 september 2006 14:46 >> To: Joe Armstrong (TN/EAB) >> Cc: [hidden email]; [hidden email] >> Subject: Re: [erlang-questions] gen_tcp question >> >> >> On 14 Sep 2006, at 13:33, Joe Armstrong ((TN/EAB)) wrote: >> >>> >>> It might well be that it >>> >>> ... "seemed to do the right thing" ... >> >> Well, It did the right thing consistently for some years with >> messages much larger that can be carried in a single LAN packet. >> Personally I would take that as greater proof than reading it >> in the documentation. >> >> Others of a different persuasion would believe that if it was >> not written in the documentation then I had in fact created a >> timebomb guaranteed to fail at the worst possible moment in >> the future ! >> >> Only Ericsson can make any documented guarantees about the >> default system, not even Tony can provide anything other that >> a statement of his intent when he wrote it. >> >> >> Sean >> >> _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Vlad Dumitrescu-2
On 14 Sep 2006, at 13:58, Vlad Dumitrescu wrote: > On 9/14/06, Sean Hinde <[hidden email]> wrote: >> Well, It did the right thing consistently for some years with >> messages much larger that can be carried in a single LAN packet. >> Personally I would take that as greater proof than reading it in the >> documentation. > > Then I suppose the problems I had (for some while ago, I think it was > R7 or R8) were not caused by this issue or was fixed since. Good to > know! Aha, but if it is not documented then YMMV! Sean _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Joe Armstrong (TN/EAB)
"Joe Armstrong (TN/EAB)" <[hidden email]> writes:
> The behaviour appears not to be documented > Meaning of {packet,N} is explained in man inet, inet:setopts The behaviour of gen_tcp:recv is explained in man gen_tcp Jani Hakala _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
On 14 Sep 2006, at 14:32, Jani Hakala wrote: > "Joe Armstrong (TN/EAB)" <[hidden email]> writes: > >> The behaviour appears not to be documented >> > Meaning of {packet,N} is explained in man inet, inet:setopts > The behaviour of gen_tcp:recv is explained in man gen_tcp Well observed! My assumption (there we go again) was that Joe must have read the documentation in order to have discover the existence of {packet, N}, but found it lacking. Reading the page more carefully now it is clear that it does specify the behaviour. Where you perchance peeking under the hood to discover this option Joe ? :-) Sean _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Vlad Dumitrescu-2
Hi,
"vladdu" <[hidden email]> writes: > There is an erlang distribution for Ubuntu, but I'm not sure how new > it is (it may be R10). I think it's to be found in the 'universe' - > just serch for erlang in synaptic. > > There is a private newer distribution, but last I checked it was only > a Debian package (meaning it would need manual setup). for those who like packages, it's also possible to compile the Debian sid Erlang source package. I did that in a clean Ubuntu 6.01.1 chroot and put the result in my private repository. The source.list line is: deb http://nxdomain.org/ubuntu dapper/ Contents right now: erlang-x11 erlang-nox erlang-src erlang-examples erlang-mode erlang erlang-base erlang-dev erlang-base-hipe erlang-doc-html erlang-manpages (all packages have version 11.b.1-1, i.e. Erlang/OTP version R11B-1) Goodbyte, Gerd. -- The last thing one knows in constructing a work is what to put first. -- Blaise Pascal _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Sean Hinde
Hi Sean,
Your assumption is correct - I did read the manual first and Jani answered a question that I had not asked. My origonal example opened the socket in active mode, and I'm not using gen_tcp:recv to receive data at all so the behaviour of recv is irrelevant. >From what's been said here, it seems I should be setting active=false and using recv, rather than doing things the way I was doing them. Why all the questions:? I'm writing THE book (at last) this means you'll just have to put up with loads of very detailed questions. This is because when I say in the book " so and so works like this ..." I want it to be correct /Joe > -----Original Message----- > From: [hidden email] > [mailto:[hidden email]] On Behalf Of Sean Hinde > Sent: den 14 september 2006 15:46 > To: Erlang Questions > Subject: Re: [erlang-questions] gen_tcp question > > > On 14 Sep 2006, at 14:32, Jani Hakala wrote: > > > "Joe Armstrong (TN/EAB)" <[hidden email]> writes: > > > >> The behaviour appears not to be documented > >> > > Meaning of {packet,N} is explained in man inet, inet:setopts The > > behaviour of gen_tcp:recv is explained in man gen_tcp > > Well observed! > > My assumption (there we go again) was that Joe must have read > the documentation in order to have discover the existence of > {packet, N}, but found it lacking. Reading the page more > carefully now it is clear that it does specify the behaviour. > > Where you perchance peeking under the hood to discover this > option Joe ? :-) > > Sean > _______________________________________________ > erlang-questions mailing list > [hidden email] > http://www.erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
Hi Joe,
If the document does not say that this can only be used in passive mode then I read it as saying it should be present and correct in active mode. The passage simply refers to "receiving", which should mean all receive modes. FWIW I was referring to active mode in my replies.. I also see that {active, once} is now properly documented which is great - it means that the book could describe the very smartest way to use sockets :-) It is truly exciting to see you are back on the book drive. I'm sure we are all here to help with your extremely welcome effort! Finally, for me the book should always refer to best "real world" practice. If Ericsson must be persuaded to fix the documentation in some areas then even better. BR, Sean On 18 Sep 2006, at 08:54, Joe Armstrong ((TN/EAB)) wrote: > Hi Sean, > > Your assumption is correct - I did read the manual first > and Jani answered a question that I had not asked. > > My origonal example opened the socket in active mode, > and I'm not using gen_tcp:recv to receive data at all > so the behaviour of recv is irrelevant. > > From what's been said here, it seems I should be setting > active=false and using recv, rather than doing things the way I was > doing > them. > > Why all the questions:? I'm writing THE book (at last) this > means you'll just have to put up with loads of very detailed > questions. This is because when I say in the book > > " so and so works like this ..." > > I want it to be correct > > /Joe > > > > >> -----Original Message----- >> From: [hidden email] >> [mailto:[hidden email]] On Behalf Of Sean Hinde >> Sent: den 14 september 2006 15:46 >> To: Erlang Questions >> Subject: Re: [erlang-questions] gen_tcp question >> >> >> On 14 Sep 2006, at 14:32, Jani Hakala wrote: >> >>> "Joe Armstrong (TN/EAB)" <[hidden email]> writes: >>> >>>> The behaviour appears not to be documented >>>> >>> Meaning of {packet,N} is explained in man inet, inet:setopts The >>> behaviour of gen_tcp:recv is explained in man gen_tcp >> >> Well observed! >> >> My assumption (there we go again) was that Joe must have read >> the documentation in order to have discover the existence of >> {packet, N}, but found it lacking. Reading the page more >> carefully now it is clear that it does specify the behaviour. >> >> Where you perchance peeking under the hood to discover this >> option Joe ? :-) >> >> Sean >> _______________________________________________ >> erlang-questions mailing list >> [hidden email] >> http://www.erlang.org/mailman/listinfo/erlang-questions >> _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Jani Hakala
Hi Jani, My problem is that I am NOT using gen_tcp:recv at all - I need to open the socket in active mode, since I want to receive both messages from the socket and send messages to the socket at the same time. I want to write a middle-man that abstracts out the TCP transport layer so I write a process that understands TCP and converts terms to packets etc. The problem occurs in the following bit of code: (C is the Pid of a client) {ok, L} = gen_tcp:listen(Port, [{length,4},binary,{active,true}]), {ok, S} = gen_tcp:accept(L), loop(S, C). loop(S, C) -> receive {tcp, S, Bin} -> %% <----- Is Bin of length 4 here????????????? C ! binary_to_term(Bin), loop(S, C); {tcp_closed, S} -> C ! closed; {msg, Term} -> gen_tcp:send(S, term_to_binary(Term)), loop(S, C); close -> gen_tcp:close(S) end I need the active=true mode for this since loop has to handle messages from both C and S - so I don't want to block in gen_tcp:recv So my question is "is Bin" fragmented? - I can easily add an extra layer for packet recombination inside loop, it is really unclear to me what the purpose of saying {packet,4} is in the listen call if it is not to be used for recombination. Now if the answer to this question is in the documentation I can't seem to find it the setopts documentation says that a 4 byte header is appended to the TCP data - that's all. The behaviour together with recv *is* documented (as you say) but not when you don't call recv and process data in active mode /Joe > -----Original Message----- > From: Jani Hakala [mailto:[hidden email]] > Sent: den 14 september 2006 15:33 > To: [hidden email] > Cc: Joe Armstrong (TN/EAB) > Subject: Re: [erlang-questions] gen_tcp question > > "Joe Armstrong (TN/EAB)" <[hidden email]> writes: > > > The behaviour appears not to be documented > > > Meaning of {packet,N} is explained in man inet, inet:setopts > The behaviour of gen_tcp:recv is explained in man gen_tcp > > Jani Hakala > _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
"Joe Armstrong (TN/EAB)" <[hidden email]> writes:
> Hi Jani, > > My problem is that I am NOT using gen_tcp:recv at all - I need to open > the socket in active mode, since I want to receive both messages from > the socket and send messages to the socket at the same time. > I didn't notice that the value {active, true} was being used implicitly (it being a default value). > I want to write a middle-man that abstracts out the TCP transport > layer so I write a process that understands TCP and converts terms to > packets etc. > > The problem occurs in the following bit of code: > > > (C is the Pid of a client) > > {ok, L} = gen_tcp:listen(Port, > [{length,4},binary,{active,true}]), > > {ok, S} = gen_tcp:accept(L), > loop(S, C). > > loop(S, C) -> > receive > {tcp, S, Bin} -> %% <----- Is Bin of length 4 > here????????????? > Length of Bin can be something between 1 byte and several megabytes. The four extra bytes inserted by using {packet,4} option are silently removed by underlying inet_drv. <clip> > I need the active=true mode for this since loop has to handle messages > from both C and S - so I don't want to block in gen_tcp:recv > > So my question is "is Bin" fragmented? - I can easily add an extra > layer for packet recombination inside loop, it is really unclear to me > what the purpose of saying {packet,4} is in the listen call if it is > not to be used for recombination. > When using {packet,PacketType}, PacketType=1,2 or 4 inet_drv receives (sends) 1, 2 or 4 byte header before the message you are receiving (sending). Those bytes correspond to one 8bit, 16bit or 32bit integer numbers that tell how long the message is going to be. The C-code in inet_drv then receives (sends) the header and the message in one or fragments which should happen under the hood. > Now if the answer to this question is in the documentation I can't > seem to find it the setopts documentation says that a 4 byte header is > appended to the TCP data - that's all. > >From inet(3erl) manpage {packet, PacketType} (TCP/IP sockets): Defines the type of packets to use for a socket. The fol- lowing values are valid: raw | 0: No packaging is done. 1 | 2 | 4: Packets consist of a header specifying the number of bytes in the packet, followed by that number of bytes. The length of header can be one, two, or four bytes; the order of the bytes is big-endian. Each send operation will generate the header, and the header will be stripped off on each receive opera- tion. asn1 | cdr | sunrm | fcgi | tpkt | line: ... Jani Hakala _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Joe Armstrong (TN/EAB)
Joe Armstrong (TN/EAB) wrote:
> {ok, L} = gen_tcp:listen(Port, > [{length,4},binary,{active,true}]), I hope it is a typo, because there's no {length, N} socket option. Did you, perhaps, mean {packet, 4}? > loop(S, C) -> > receive > {tcp, S, Bin} -> %% <----- Is Bin of length 4 > here????????????? > C ! binary_to_term(Bin), > loop(S, C); > {tcp_closed, S} -> > C ! closed; > {msg, Term} -> > gen_tcp:send(S, term_to_binary(Term)), > loop(S, C); > close -> > gen_tcp:close(S) > end I wouldn't be able to say how this was *supposed* to work since this is unclear from the documentation. However, by knowing the details of the inet_drv C driver I can tell you that the difference in the driver behavior in presence of the {active, true} option is that in contrast to the gen_tcp:recv/2, when the driver is getting a command from the Erlang process to issue a socket read, the active option initiates a socket read upon detecting some data on the socket in exactly the same manner as if the gen_tcp:recv(Sock, 0) was called. In both cases you are guaranteed to get the *full non-fragmented* packet of length M (where M is read from the message header determined by the N bytes with respect to the {packet, N} option). Note that since gen_tcp:recv(Sock, M), where M > 0 is not a possible call for sockets with {packet, N} where N =/= 0, it would also be meaningless to have the {packet, N} option if it didn't guarantee non-fragmented delivery of packets. > I need the active=true mode for this since loop has to handle messages > from both C and S - so I don't want to block in gen_tcp:recv Since you are including this example in the book, I'd recommend additionally showing how to use active sockets and still preserve flow control without gen_tcp:recv, so that you can implement the server using the standard OTP gen_server behavior. This can be accomplished by using {active, once} option. > Now if the answer to this question is in the documentation I can't seem > to find it > the setopts documentation says that a 4 byte header is appended to the > TCP data - that's > all. I also don't believe this is documented. Regards, Serge >> -----Original Message----- >> From: Jani Hakala [mailto:[hidden email]] >> Sent: den 14 september 2006 15:33 >> To: [hidden email] >> Cc: Joe Armstrong (TN/EAB) >> Subject: Re: [erlang-questions] gen_tcp question >> >> "Joe Armstrong (TN/EAB)" <[hidden email]> writes: >> >>> The behaviour appears not to be documented >>> >> Meaning of {packet,N} is explained in man inet, inet:setopts >> The behaviour of gen_tcp:recv is explained in man gen_tcp >> >> Jani Hakala >> > > _______________________________________________ > erlang-questions mailing list > [hidden email] > http://www.erlang.org/mailman/listinfo/erlang-questions > _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
|
In reply to this post by Joe Armstrong (TN/EAB)
Joe,
See in-line comments. Joe Armstrong (TN/EAB) wrote: > Hi Serge, > > It seems to me that the program "does the right thing" (ie recombines > fragmented packets if packet>0) but that this fact is not documented. > > I can understand that {packet,4} adds a 4 byte header on transmission > so for example, a C program can read this and do whever it wants. > > But since the packet,4 header is silently removed in the Erlang case > (with an active socket) then it become invisible, so I have to add my > own private size(BIN) (as 4 bytes) in front of each Binary I send > and then do a re-entrant package reassembly in Erlang (not difficult, > but it seems a bit daft, since in this case I could just have used > packet,0 > and done the reassembly anyway) > > Sean, claims that packets are not fragmented, ie that the driver > reassembles the packets in the case when a packet length is > given, ie does the right thing Yes, I concur with Sean's claim. > Jani said in his last mail > > Jani> When using {packet,PacketType}, PacketType=1,2 or 4 inet_drv > receives > Jani> (sends) 1, 2 or 4 byte header before the message you are receiving > (sending). Those bytes > Jani> correspond to one 8bit, 16bit or 32bit integer numbers that tell > how long the message is going Jani> to be. The C-code in inet_drv then > receives (sends) the header and the message in one or > Jani> fragments which should happen under the hood. > > I think this is the opposite of what Sean says > > I'm not really sure what " .. and the message in one or two fragments > .." means. I am not clear about this sentence either, but I believe Jani meant the same thing as Sean. [...] > It seems to me that the logical behaviour if a packet size is given is > that the > Erlang messages are delivered from and to the driver in unfragmented > binaries > and that the messages on the line are preceded by a header and then > possible fragmented. Correct. It would be infeasible to assume that messages can be not fragmented on the transport layer, as it's beyond the control of the C driver used by the emulator, and is fully dependent on the underlying protocol. For instance, in case of SCTP the protocol preserves message boundaries, so a receive call on an SCTP socket would always guarantee that a message is either delivered in full, or an error is generated. > I gave up and started reading inet_drv.c - somewhere in 7071 lines of is > the answer ... > but it's not obvious to me where this is ... You can examine the following functions: tcp_recv() tcp_remain() tcp_deliver() > I didn't really understand this comment > >> Since you are including this example in the book, I'd >> recommend additionally showing how to use active sockets and >> still preserve flow control without gen_tcp:recv, so that you >> can implement the server using the standard OTP gen_server >> behavior. This can be accomplished by using {active, once} option. > > Can you expand on this with (possibly) an example? Surely! Let's say that we wanted to accomplish the following: 1. Implement a TCP server receiving client connection requests, and communicating over some custom protocol. 2. Ensure that there's flow control on the server side and that clients will not bring down the server by over-flooding its message queue. 3. Use standard OTP behaviors to implement the server process handling client transactions. Now, say we learn how to accomplish #1 by studying your tcp_server tutorial: http://www.sics.se/~joe/tutorials/web_server/tcp_server.erl #2 can be accomplished by ensuring that if too much traffic is being generated by clients, we have control over how that traffic is dispatched to the mailbox of the Erlang server process handling client's transactions. This is done by either: a. Using blocking gen_tcp:recv/2 socket calls. In this case the Erlang process actively reads data from the socket's buffer, and this data doesn't reach server process mailbox. The drawback of this approach is that it introduces a blocking behavior to the process, and we cannot use selective receive to respond to other messages coming to the process mailbox. b. Using the {active, once} server socket option, and not using the blocking gen_tcp:recv/2 call, but relying on the gen_tcp's ability to read and deliver *one* message to the mailbox of the server process. This is great because we no longer have to deal with blocking calls in the program, and can use standard gen_server behavior to implement the server. The trick is that after receiving and processing a message from the mailbox, the server needs to issue a call to inet:setopts(Sock, [{active, once}]) to allow the gen_tcp socket to deliver the next message. #3 is illustrated by the example below. Note that I am only including a few gen_server callbacks that illustrate this point. -module(custom_server). -behavior(gen_server). % Create a new process handling interactions with the client. If this % server was a part of an application with a supervisor, we could use % the simple_one_for_one restart strategy in the supervisor for these % server processes. In this case in a production system a crash of % such a server would automatically generate and log an error report by % the supervisor / SASL. The difference in server creation then would % that we'd call supervisor:start_child/2 instead of gen_server:start % to create the server process. new_client(Socket) -> {ok, Pid} = gen_server:start(?MODULE, [Socket], []), % Here we assume that the calling process had the ownership of the % socket. We need to delegate that ownership to the newly created % gen_server in order for the active socket to deliver messages to % the proper Pid. ok = gen_tcp:controlling_process(Socket, Pid), {ok, Pid}. ... % Let's assume that the socket is created by init([Socket]) -> inet:setopts(Socket, [{active, once}, {packet, 4}, binary]), ... {ok, State#state{sock = Socket}}. handle_info({tcp, Socket, Data}, #state{sock=Socket} = State) -> % Note that Data is delivered non-fragmented here NewState = do_handle_request(Socket, Data, State), inet:setopts(Socket, [{active, once}]), {noreply, NewState}; ... Please note the following: 1. It is not clear from documentation if the socket returned from the acceptor call inherits any options given to the listen socket. I.e. if the listen socket was opened with: {ok, ListenSocket} = listen(Port, [{packet, 4}]). would the server process accepting the client socket need to explicitly call inet:setopts(Socket, [{packet, 4}]) after the following statement? {ok, Socket} = accept(ListenSocket). Or is that option inherited from the listener socket? I don't think any options are inherited, and call that explicitly, but it would be nice if documentation mentioned something about it. 2. Is it possible to turn the socket acceptor process into a gen_server? The gen_tcp:accept/1 call is blocking by nature, and I don't see how this could be done. However, this server pattern is fairly generic, and it would be nice if it could be completely mapped to some OTP behavior. Regards, Serge > Thanks a lot > > /Joe > > >> -----Original Message----- >> From: Serge Aleynikov [mailto:[hidden email]] >> Sent: den 18 september 2006 16:45 >> To: Joe Armstrong (TN/EAB) >> Cc: [hidden email] >> Subject: Re: [erlang-questions] gen_tcp question >> >> Joe Armstrong (TN/EAB) wrote: >>> {ok, L} = gen_tcp:listen(Port, >>> [{length,4},binary,{active,true}]), >> I hope it is a typo, because there's no {length, N} socket >> option. Did you, perhaps, mean {packet, 4}? >> >>> loop(S, C) -> >>> receive >>> {tcp, S, Bin} -> %% <----- Is Bin of length 4 >>> here????????????? >>> C ! binary_to_term(Bin), >>> loop(S, C); >>> {tcp_closed, S} -> >>> C ! closed; >>> {msg, Term} -> >>> gen_tcp:send(S, term_to_binary(Term)), >>> loop(S, C); >>> close -> >>> gen_tcp:close(S) >>> end >> I wouldn't be able to say how this was *supposed* to work >> since this is unclear from the documentation. However, by >> knowing the details of the inet_drv C driver I can tell you >> that the difference in the driver behavior in presence of the >> {active, true} option is that in contrast to the >> gen_tcp:recv/2, when the driver is getting a command from the >> Erlang process to issue a socket read, the active option >> initiates a socket read upon detecting some data on the >> socket in exactly the same manner as if the >> gen_tcp:recv(Sock, 0) was called. In both cases you are >> guaranteed to get the *full non-fragmented* packet of length >> M (where M is read from the message header determined by the >> N bytes with respect to the {packet, N} option). >> >> Note that since gen_tcp:recv(Sock, M), where M > 0 is not a >> possible call for sockets with {packet, N} where N =/= 0, it >> would also be meaningless to have the {packet, N} option if >> it didn't guarantee non-fragmented delivery of packets. >> >>> I need the active=true mode for this since loop has to >> handle messages >>> from both C and S - so I don't want to block in gen_tcp:recv >> Since you are including this example in the book, I'd >> recommend additionally showing how to use active sockets and >> still preserve flow control without gen_tcp:recv, so that you >> can implement the server using the standard OTP gen_server >> behavior. This can be accomplished by using {active, once} option. >> >>> Now if the answer to this question is in the documentation I can't >>> seem to find it the setopts documentation says that a 4 >> byte header is >>> appended to the TCP data - that's all. >> I also don't believe this is documented. >> >> Regards, >> >> Serge >> >>>> -----Original Message----- >>>> From: Jani Hakala [mailto:[hidden email]] >>>> Sent: den 14 september 2006 15:33 >>>> To: [hidden email] >>>> Cc: Joe Armstrong (TN/EAB) >>>> Subject: Re: [erlang-questions] gen_tcp question >>>> >>>> "Joe Armstrong (TN/EAB)" <[hidden email]> writes: >>>> >>>>> The behaviour appears not to be documented >>>>> >>>> Meaning of {packet,N} is explained in man inet, inet:setopts The >>>> behaviour of gen_tcp:recv is explained in man gen_tcp >>>> >>>> Jani Hakala >>>> >>> _______________________________________________ >>> erlang-questions mailing list >>> [hidden email] >>> http://www.erlang.org/mailman/listinfo/erlang-questions >>> >> > _______________________________________________ erlang-questions mailing list [hidden email] http://www.erlang.org/mailman/listinfo/erlang-questions |
| Powered by Nabble | Edit this page |
