I was wondering if there was some scenario where %INFO could actually be an empty hash. Thanks for clarifying that you've thought about that. Also, the possible 10K message is significant.
In your child, the autoflush part looks good to me. However, I am not sure exactly what will happen with more than one send buffer's worth of data. Probably the buffer size is 4K as a good guess. The "print" will not be "atomic". Could be separate 4K, 4K, then 2K writes.
In your parent, $num = read($child_fh, $buf, 1e6); you are assuming that all of the data that the child sent is available at once. Usually that will be true (what the child does is very fast), but sometimes that may not be true. What happens if you read the pipe between the sending of one of child's buffers? You would get everything sent so far, but perhaps not all that will be sent by the child. If the child has only put a single 4K packet into the pipe and is still working on the next one, your statement will just ignore the data that is to come.
Your parent read loop should read data until is sees ":DONE:". It probably would be ok to use a blocking call for this on a line by line basis. The reasoning is that the child's transmission job is fast. If a buffer containing the lines received don't start with ":MSG:", then you have a malformed message. I see no reason for state $collected; I would just use a normal "my" variable with appropriate scope.
You actually have a fair amount of time that can be spent in the parent read routine. You are reading this pipe because you got a notification that at least one byte was available. The child will be sending all of the other bytes forthwith. Make sure that you are getting the entire message. The GUI user will not notice a couple of ms of delay.
Update: If I understand correctly, you are getting about 8,640 messages per day (once every 10 seconds). One out of 20-30K messages fails? This one time per 25K sounds like an inter-process com failure. I would put some code in to detect "malformed message" (got DONE, but buffer doesn't start with MSG).
Update: I was thinking about this some more and if you were randomly polling the client, this kind of thing wouldn't happen nearly as often as once per 20K times - you are seeing a problem "relatively often". However, you have special "push" situation that increase the probability of an error. The parent will be notified very soon after a large data buffer is starting to be written to the pipe - I would think at least after the first 4k. The parent could get to the pipe before the client finishes sending. You could wind up with a partial message or a message containing fragments from a previously not completely received message.
I very much like the idea of what you did with adding :MSG: and :DONE: The parent should wind up synchronized so that it only gets complete messages, one at a time. After you see a :DONE: line, I don't think that there is any tricky stuff that you need to do in case there is another message "stacked behind" that one. The client only sends these things once every 10 seconds. When you see the :DONE: line, if the buffer doesn't have :MSG: right at the start of it, then you have a framing error. If there are no framing errors, then we into a different kind of mystery. Once established, you can assume that a connection like you have is without transmission errors.
Change the parent read loop to look for ":DONE" do not assume that a single read will do that.
To be more specific, (untested of course), in the child:
put beginning and ending key words on separate lines
change print $parent_fh ":MSG:${dumped}:DONE:\n";
to print $parent_fh ":MSG:\n${dumped}\n:DONE:\n";
In the parent - something like this...:
I assuming that there is no real performance issue here at all. And if this is 10K chars per 10 secs, there won't be.# OK to use blocking calls, the data will be there # don't read past the "DONE", wait for next file event # otherwise this will "hang". my $msg; while (my $line = <$child_fh>) { $msg =. $line; last if $line =~ /^:DONE:\s*$/; } if ($msg !~ /^:MSG:/) {framing error!} do what you need to do... $msg = undef;
In reply to Re^3: Help requested to find the cause of an "uninitialized value" message
by Marshall
in thread Help requested to find the cause of an "uninitialized value" message
by andyok
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |