Recieve packet from socket in Erlang active mode with ASCII packet size header

George Hope george@REDACTED
Mon Jan 4 15:40:48 CET 2021


By synchronous I mean if the program does not finish processing processing of first packet and packet 2,3 arrived does Erlang VM wait for handle_info to return? Is it possible to lose sequnce of packets?As far as I know handle_call is sync and handle_cast is async in gen_server. ---- On Mon, 04 Jan 2021 17:50:48 +0330  jesper.louis.andersen@REDACTED  wrote ----On Mon, Jan 4, 2021 at 2:40 PM George Hope <george@REDACTED> wrote:my questions are: 1. is there a better way to do this? last time I made a mistake and read some messages more than once(I fixed that bug, but did not test my code in production yet, but it seems OK in tests). when packet size is unsigned integer Erlang can handle this for me but no success with ASCII encoded packet size. 2. I tried to use {active, once} and  gen_tcp:recv but It did not work properly for me, Is this a safer approach? 3. Is gen_server:handle_info synchronous? 1. Rough idea:When you get a new bin in, you can probably just append it directly:handle_info({ConnType, _Sock, Data}, SoFar) ->    read_iso_packet(<<SoFar/binary, Data/binary>>, ...).This then makes the rest of the code simpler since it can just inspect that singular data block, trying to cut the head out of the binary in order to decode the ASCII value. Some solutions will return either {more, N, Bin} if more data is needed (N bytes) or {packet, Packet, Rest} if a packet was decoded. You then loop again on Rest after having handled the packet because you might have enough data for the next message already in the buffer. But this depends a bit on your socket mode being active or passive. It's often easier to just try decoding from the head. If you can get a full packet out, process and recur. If you don't have enough data, stuff it into the buffer and wait for more data to arrive. Unless you are looking at very high loads this is going to be efficient.2. {active, once} and {active, N} are very recommended! You call inet:setopts/2 on the socket once you have received a message:handle_info({ConnType, Socket, Data}, #state { socket = Socket, buffer = SoFar} = State) ->    ok = inet:setopts(Socket, [{active, once}]),    read_iso_packet(<<SoFar/binary, Data/binary>>, State);It allows you to do other things in the process while you are waiting on the network socket for more data, increasing responsiveness of your system. Furthermore, it provides backpressure on the TCP socket if you end up in a situation where the sender outpaces your receiver. {active, once} is probably fast enough for most cases.3. It's not clear what you mean by synchronous here. Other TCP data might arrive on the socket while you are executing handle_info/2 but as soon as you return it'll get called again with the new data. There's only a single process executing the handle_info/2 call, so you have some very neat linearity guarantees and you don't have to worry about a lot of problems that would normally be present in code using critical sections (mutexes, condition variables, ...).-- J.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20210104/540d5fe3/attachment.htm>


More information about the erlang-questions mailing list