A reference to a hash member? (to an object's member variable)

A

A. Farber

Hello,

I have an object, which reads a header
from a non-blocking socket and if the header
indicates, that there is more data to read
(a chat string) then it will read that too.

To handle those 2 reading states
(reading a header; reading a chat string)
I try to use 3 variables: $buf, $toread, $offset
and then call sysread($buf, $toread, $offset).

My problem is, that I need to set
$buf to _point_ to $self->{REQ_HEADER}
in the 1st state and to $self->{CHAT}
in the 2nd state. But I don't know how.

In C-code (which I'm trying to port to Perl)
this has been very easy. But in Perl I don't
know how and rereading "perlref" doesn't help.

Any hints please?
Alex

PS: My complete, but buggy code is below:

sub read {
my $self = shift;
my $fh = $self->{FH};
my ($buf, $toread, $offset, $nbytes);

# start or continue reading the request header
if ($self->{NREAD} < REQ_HEADER_LEN) {
$buf = $self->{REQ_HEADER};
$offset = $self->{NREAD};
$toread = REQ_HEADER_LEN - $offset;
# start or continue reading the chat string
} else {
$buf = $self->{CHAT};
$offset = $self->{NREAD} - REQ_HEADER_LEN;
$toread = $self->{LEN} - $offset;
}

# XXX the buf is WRONG here:
$nbytes = $fh->sysread($buf, $toread, $offset);

unless (defined $nbytes) {
# interrupted by signal or would block - retry later
return if $!{EINTR} || $!{EAGAIN} || $!{EWOULDBLOCK};
# connection interrupted - remove the Apache child
$self->remove($fh);
return;
}

if (0 == $nbytes) {
# connection closed - remove the Apache child
$self->remove($fh);
return;
}

$self->{NREAD} += $nbytes;
print STDERR "nbytes = $nbytes\n";

# not done yet - continue reading
return if $nbytes < $toread;

if (REQ_HEADER_LEN == $self->{NREAD}) {
($self->{SID}, $self->{EVENT}, $self->{MOD}, $self-
unpack 'A32xN3', $self->{REQ_HEADER};

printf STDERR "sid=%s, event=%x, mod=%x, len=%x\n",
$self->{SID}, $self->{EVENT}, $self->{MOD}, $self-

# not done yet - continue reading (the chat string)
return if $self->{LEN} > 0;
}

print STDERR "done reading";
#$Poll->mask($fh => POLLOUT);
}
 
S

sln

Hello,

I have an object, which reads a header
from a non-blocking socket and if the header
indicates, that there is more data to read
(a chat string) then it will read that too.

To handle those 2 reading states
(reading a header; reading a chat string)
I try to use 3 variables: $buf, $toread, $offset
and then call sysread($buf, $toread, $offset).

My problem is, that I need to set
$buf to _point_ to $self->{REQ_HEADER}
in the 1st state and to $self->{CHAT}
in the 2nd state. But I don't know how.

In C-code (which I'm trying to port to Perl)
this has been very easy. But in Perl I don't
know how and rereading "perlref" doesn't help.

Any hints please?
Alex

PS: My complete, but buggy code is below:

sub read {
my $self = shift;
my $fh = $self->{FH};
my ($buf, $toread, $offset, $nbytes);

# start or continue reading the request header
if ($self->{NREAD} < REQ_HEADER_LEN) {
$buf = $self->{REQ_HEADER};
$offset = $self->{NREAD};
$toread = REQ_HEADER_LEN - $offset;
# start or continue reading the chat string
} else {
$buf = $self->{CHAT};
$offset = $self->{NREAD} - REQ_HEADER_LEN;
$toread = $self->{LEN} - $offset;
}

# XXX the buf is WRONG here:
$nbytes = $fh->sysread($buf, $toread, $offset);

unless (defined $nbytes) {
# interrupted by signal or would block - retry later
return if $!{EINTR} || $!{EAGAIN} || $!{EWOULDBLOCK};
# connection interrupted - remove the Apache child
$self->remove($fh);
return;
}

if (0 == $nbytes) {
# connection closed - remove the Apache child
$self->remove($fh);
return;
}

$self->{NREAD} += $nbytes;
print STDERR "nbytes = $nbytes\n";

# not done yet - continue reading
return if $nbytes < $toread;

if (REQ_HEADER_LEN == $self->{NREAD}) {
($self->{SID}, $self->{EVENT}, $self->{MOD}, $self-
unpack 'A32xN3', $self->{REQ_HEADER};

printf STDERR "sid=%s, event=%x, mod=%x, len=%x\n",
$self->{SID}, $self->{EVENT}, $self->{MOD}, $self-

# not done yet - continue reading (the chat string)
return if $self->{LEN} > 0;
}

print STDERR "done reading";
#$Poll->mask($fh => POLLOUT);
}

I don't know for sure if "$fh->sysread() is valid (it may be),
but did you try this:

$nbytes = sysread($fh, $buf, $toread, $offset);

-------

sysread FILEHANDLE,SCALAR,LENGTH,OFFSET

Also, OFFSET, in this case, is not the file offset. But I don't
know what your trying to achieve.

"An OFFSET may be specified to place the read data at some place in
the string other than the beginning. A negative OFFSET specifies
placement at that many characters counting backwards from the end
of the string. A positive OFFSET greater than the length of SCALAR
results in the string being padded to the required size with "\0"
bytes before the result of the read is appended"


sln
 
B

Ben Morrow

Quoth "A. Farber said:
Hello,

I have an object, which reads a header
from a non-blocking socket and if the header
indicates, that there is more data to read
(a chat string) then it will read that too.

To handle those 2 reading states
(reading a header; reading a chat string)
I try to use 3 variables: $buf, $toread, $offset
and then call sysread($buf, $toread, $offset).

My problem is, that I need to set
$buf to _point_ to $self->{REQ_HEADER}
in the 1st state and to $self->{CHAT}
in the 2nd state. But I don't know how.

Use

$bufref = \$self->{REQ_HEADER};

to take a reference, and

sysread($$bufref, $toread, $offset);

to read into the variable referenced. Now go and reread perlref (again
:) ) and figure out why it works. Note that the first line parses as

$bufref = \( $self->{REQ_HEADER} );

and you could write it like that if you think it's clearer.

If you really object to the explicit ref syntax, you could use
Data::Alias:

use Data::Alias;

alias $buf = $self->{REQ_HEADER};

but you will need to learn to use references, in the long run.

Ben
 
S

sln

I don't know for sure if "$fh->sysread() is valid (it may be),
but did you try this:

$nbytes = sysread($fh, $buf, $toread, $offset);

-------

sysread FILEHANDLE,SCALAR,LENGTH,OFFSET

Also, OFFSET, in this case, is not the file offset. But I don't
know what your trying to achieve.

"An OFFSET may be specified to place the read data at some place in
the string other than the beginning. A negative OFFSET specifies
placement at that many characters counting backwards from the end
of the string. A positive OFFSET greater than the length of SCALAR
results in the string being padded to the required size with "\0"
bytes before the result of the read is appended"


sln

It is possible that "reads" need a reference to a buffer, I'm not
sure.

So, something like this would be necessary:

$buf = \$self->{REQ_HEADER};

unless $self->{REQ_HEADER} is already a SCALAR reference.

Not sure.


sln
 
X

xhoster

A. Farber said:
sub read {
my $self = shift;
my $fh = $self->{FH};
my ($buf, $toread, $offset, $nbytes);

# start or continue reading the request header
if ($self->{NREAD} < REQ_HEADER_LEN) {
$buf = $self->{REQ_HEADER};

Replace above line with $key ="REQ_HEADER";

$offset = $self->{NREAD};
$toread = REQ_HEADER_LEN - $offset;
# start or continue reading the chat string
} else {
$buf = $self->{CHAT};

replace with $key = "CHAT";
$offset = $self->{NREAD} - REQ_HEADER_LEN;
$toread = $self->{LEN} - $offset;
}

# XXX the buf is WRONG here:
$nbytes = $fh->sysread($buf, $toread, $offset);

replace with

$nbytes = $fh->sysread($self->{$key}, $toread, $offset);

(or use references)

Xho

--
-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top