T
travislspencer
Hey All,
I am trying to write a little TCP server. The format of the protocol
it and its clients speak is a proprietary one. The data isn't line
oriented in any way; however, most of the examples I've seen delimited
requests and responses using a new line as in the reader sub described
on http://tinyurl.com/z7b7r.
My question is this: how can I write a TCP server that will accept
exactly the amount of data sent to it from its client. At first, my
server wasn't accepting all of the clients packets. I fixed this by
using the IO::Select module; however, now it reads too much. At the
moment, this is the server:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Select;
use IO::Socket;
my $server = IO::Socket::INET->new(LocalPort => 7142,
Type => SOCK_STREAM,
Reuse => 1,
Listen => SOMAXCONN)
|| die "Couldn't act as a TCP server on $port: $@\n";
my $select = IO::Select->new();
while (my $client = $server->accept()) {
$select->add($client);
while ($select->can_read()) {
my $buf;
my %packet;
$client->sysread($buf, 5);
$packet{command} = unpack("n", $buf);
$packet{product_id} = unpack("xxC", $buf);
$packet{model_code} = unpack("xxxC", $buf) >> 4;
$packet{data_length} = unpack("xxxn", $buf) & 0xFFF;
$client->sysread($buf, $packet{data_length});
# TODO: Put the data into the packet structure.
$client->sysread($buf, 1);
$packet{checksum} = unpack("C", $buf);
# Do work w/ %packet lick verifying its checksum,
# responding to its command, etc.
}
$select->remove($client);
}
close($server);
I am trying to test it with this client:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
use IO::Select;
my $host = "127.0.0.1";
my $socket = IO::Socket::INET->new(PeerAddr => $host,
PeerPort => 7142,
Type => SOCK_STREAM)
|| die "Couldn't connect to $host:$port: $@\n";
print $socket pack("C7",
0xcc, # Command ID 1
0x81, # Command ID 2
0xF, # Product ID
0xF0, # Model code & high 4 bits of length
1, # Low 8 bits of data length
0x76, # data
0x44 # Checksum
);
print $socket pack("C7",
0xcc,
0x81,
0xF,
0xF0,
1,
0x76,
0x44
);
close($socket);
The server starts fine; however, when I run the client, I get this
error:
'x' outside of string in unpack at ./pseudopd line 34.
This happens after the server reads both packets that the client sent
to it. Line 34 is this one:
$packet{product_id} = unpack("xxC", $buf);
I have poured over the server code for too long and surfed around the
Net. I'm starting to think that the client is broken, but I wanted to
ask if anyone could spot my mistake. I'm really new to this stuff, so
I would really appreciate a hand.
I am trying to write a little TCP server. The format of the protocol
it and its clients speak is a proprietary one. The data isn't line
oriented in any way; however, most of the examples I've seen delimited
requests and responses using a new line as in the reader sub described
on http://tinyurl.com/z7b7r.
My question is this: how can I write a TCP server that will accept
exactly the amount of data sent to it from its client. At first, my
server wasn't accepting all of the clients packets. I fixed this by
using the IO::Select module; however, now it reads too much. At the
moment, this is the server:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Select;
use IO::Socket;
my $server = IO::Socket::INET->new(LocalPort => 7142,
Type => SOCK_STREAM,
Reuse => 1,
Listen => SOMAXCONN)
|| die "Couldn't act as a TCP server on $port: $@\n";
my $select = IO::Select->new();
while (my $client = $server->accept()) {
$select->add($client);
while ($select->can_read()) {
my $buf;
my %packet;
$client->sysread($buf, 5);
$packet{command} = unpack("n", $buf);
$packet{product_id} = unpack("xxC", $buf);
$packet{model_code} = unpack("xxxC", $buf) >> 4;
$packet{data_length} = unpack("xxxn", $buf) & 0xFFF;
$client->sysread($buf, $packet{data_length});
# TODO: Put the data into the packet structure.
$client->sysread($buf, 1);
$packet{checksum} = unpack("C", $buf);
# Do work w/ %packet lick verifying its checksum,
# responding to its command, etc.
}
$select->remove($client);
}
close($server);
I am trying to test it with this client:
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket;
use IO::Select;
my $host = "127.0.0.1";
my $socket = IO::Socket::INET->new(PeerAddr => $host,
PeerPort => 7142,
Type => SOCK_STREAM)
|| die "Couldn't connect to $host:$port: $@\n";
print $socket pack("C7",
0xcc, # Command ID 1
0x81, # Command ID 2
0xF, # Product ID
0xF0, # Model code & high 4 bits of length
1, # Low 8 bits of data length
0x76, # data
0x44 # Checksum
);
print $socket pack("C7",
0xcc,
0x81,
0xF,
0xF0,
1,
0x76,
0x44
);
close($socket);
The server starts fine; however, when I run the client, I get this
error:
'x' outside of string in unpack at ./pseudopd line 34.
This happens after the server reads both packets that the client sent
to it. Line 34 is this one:
$packet{product_id} = unpack("xxC", $buf);
I have poured over the server code for too long and surfed around the
Net. I'm starting to think that the client is broken, but I wanted to
ask if anyone could spot my mistake. I'm really new to this stuff, so
I would really appreciate a hand.