I'm trying to script battleship with perl, which can be played over the network.
The problem is that i'm just able to print on the same console, but not on other consoles through the socket.
Client:
$socket = new IO::Socket::INET(
PeerHost => '127.0.0.1',
PeerPort => '5005',
Protocol => 'tcp'
) or die "Socket konnte nicht erstellt werden!\n$!\n";
print "Client kommuniziert auf Port 5005\n";
while ( $eing ne ".\n" ) {
$eing = <> ;
print $socket "$eing";
}
Server:
$socket = new IO::Socket::INET(
LocalHost => '127.0.0.1',
LocalPort => '5005',
Protocol => 'tcp',
Listen => 5,
Reuse => 1
) or die "Socket konnte nicht erstellt werden!\n$!\n";
while ( 1 ) {
$client_socket = $socket -> accept();
$peeraddress = $client_socket -> peerhost();
$peerport = $client_socket -> peerport();
$eing = "";
while ( $eing ne ".\n" ) {
print "while";
&ausgabe;
}
}
sub ausgabe {
foreach $crt_board (#board2) {
foreach $spalte (#$crt_board) {
print $client_socket "$spalte ";
}
print $client_socket "\n";
}
}
The result should be an board which looks like this.
1 2 3 4 5
1 ? ? ? ? ?
2 ? ? ? ? ?
3 ? ? ? ? ?
4 ? ? ? ? ?
5 ? ? ? ? ?
You need to read from a socket if you want transfer data from server to client, or vice versa. Do always use strict (and warnings). The following will get you started:
Client:
use strict;
use IO::Socket::INET;
my $socket = new IO::Socket::INET(
PeerHost => '127.0.0.1',
PeerPort => '5005',
Protocol => 'tcp'
) or die "Socket konnte nicht erstellt werden!\n$!\n";
print "Client kommuniziert auf Port 5005\n";
while ( 1 ) {
my $data;
$socket->recv($data, 64);
print $data;
last if $data =~ m#\.\n#;
}
Server:
use strict;
use IO::Socket::INET;
my $socket = new IO::Socket::INET(
LocalHost => '127.0.0.1',
LocalPort => '5005',
Protocol => 'tcp',
Listen => 5,
Reuse => 1
) or die "Socket konnte nicht erstellt werden!\n$!\n";
while ( my $client_socket = $socket -> accept() ) {
my $peeraddress = $client_socket -> peerhost();
my $peerport = $client_socket -> peerport();
ausgabe($client_socket);
}
sub ausgabe {
my $client_socket = shift;
my #board2 = ([" ", 1,2,3],[1,"?","?","?"],
[2,"?","?","?"], [3,"?","?","?"]);
foreach my $crt_board (#board2) {
foreach my $spalte (#$crt_board) {
$client_socket->send("$spalte ");
}
$client_socket->send("\n");
}
$client_socket->send(".\n");
}
Related
I have the following Socks Server
my $socks_server = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => 8000,
Listen => 1,
) or die "socket error";
while(1) {
my $client = $socks_server->accept();
print $client;
unless ($client) {
print "ERROR:";
next;
}
}
and the following Socks Client
use strict;
use warnings;
use IO::Socket::Socks;
my $socks_client = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => "8000",
) or die $SOCKS_ERROR;
print $socks_client "foo\n";
$socks_client->close();
the Socks client print "foo\n" , how can I let the Socks Server print it to the console when its received?
Following code is provided for demonstration purpose only, authentication is turned off for simplicity.
The code is based on documetation for IO::Socket::Socks
Code for server.pl
use strict;
use warnings;
use feature 'say';
use IO::Socket::Socks ':constants';
my $SOCKS_ERROR = 'Error: SOCKS';
my $socks_server = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => 8000,
Listen => 1,
UserAuth => \&auth,
RequireAuth => 0
) or die $SOCKS_ERROR;
while(1) {
my $client = $socks_server->accept();
unless ($client) {
print "ERROR: $SOCKS_ERROR\n";
next;
}
my $command = $client->command();
if ($command->[0] == CMD_CONNECT) {
# Handle the CONNECT
$client->command_reply(REPLY_SUCCESS, 'localhost', 8000);
}
print while <$client>;
$client->close();
}
sub auth {
my ($user, $pass) = #_;
return 1 if $user eq "foo" && $pass eq "bar";
return 0;
}
Code for client.pl
use strict;
use warnings;
use feature 'say';
use IO::Socket::Socks;
my $socks_client = IO::Socket::Socks->new(
ProxyAddr => "localhost",
ProxyPort => "8000",
ConnectAddr => "localhost",
ConnectPort => "8022",
) or die $SOCKS_ERROR;
print $socks_client $_ for <DATA>;
$socks_client->close();
__DATA__
-----------------------------------------------
This a test message sent from remote client for
SOCKS demonstration code.
Enjoy your day.
Output on server.pl side
C:\....\examples\socks_server.pl
-----------------------------------------------
This a test message sent from remote client for
SOCKS demonstration code.
Enjoy your day.
Output on client.pl side
C:\...\examples\socks_client.pl
C:\...>
I have some realization of bind, connect to SOCKS and connect to SMTP server through SOCKS. How i can use this connect with SSL/TLS NET::SMTP? This question not help me, because SSL handshake can't start.
DEBUG: .../IO/Socket/SSL.pm:683: waiting for fd to become ready: SSL wants a read first
DEBUG: .../IO/Socket/SSL.pm:693: handshake failed because socket did not became ready
Here realization of connect to remote server via proxy:
sub connect {
my ($ip, $port, $is_ssl, $pid, $server) = #_;
if (defined $socket) {
my ($packed_cmd, $buffer, #data, %response);
$packed_cmd = pack("C4Nn", 0x05, 0x01, 0x00, 0x01, $ip, $port);
$socket->send($packed_cmd);
if (defined $socket->recv($buffer, 1024)) {
#data = unpack("C4 L S", $buffer);
$response{'version'} = $data[0];
$response{'result'} = $data[1];
$response{'reg'} = $data[2];
$response{'type'} = $data[3];
$response{'ip'} = $data[4];
$response{'port'} = $data[5];
$socket->blocking(0);
if ($is_ssl) {
&debug(3, $pid, "Try start SSL handshake with [$server]\n");
IO::Socket::SSL->start_SSL($socket, SSL_version => 'SSLv23', SSL_ca_file => SSL_CA_FILE) or &debug(3, $pid, "Cannot start SSL handshake! $#\n") and return 0;
&debug(3, $pid, "SSL handshake done!\n");
}
# TODO: Make TLS support
return 1;
}
}
&debug(3, $pid, "Cannot connect to [$server:$port] through socks server [$socks_name:$socks_server]\n");
return 0;
}
Bind SOCKS
sub bind_socks {
my ($pid) = #_;
my ($method, $packed_cmd, $buffer, #data, %response);
$socket = IO::Socket::INET->new(
PeerAddr => $socks_server,
PeerPort => $socks_port,
Proto => 'tcp',
Timeout => SOCKS5_CONNECT_TIMEOUT
) or &debug(3, $pid, "Cannot connect to the socks server [$socks_server] $#\n") and return 0;
&debug(3, $pid, "Connected to the socks server [$socks_name:$socks_server]\n");
$socket->blocking(1);
if ($socks_username && $socks_password) {
$method = 0x02;
} else {
$method = 0x00;
}
$packed_cmd = pack("C3", 0x05, 0x01, $method);
$socket->send($packed_cmd);
if (defined $socket->recv($buffer, 1024)) {
#data = unpack("C2", $buffer);
$response{'version'} = $data[0];
$response{'method'} = $data[1];
if ((defined $response{'version'}) && (defined $response{'method'}) && ($response{'version'} eq 5) && ($response{'method'} eq $method)) {
if ($method == 2) {
$packed_cmd = pack("CC", 0x01, length($socks_username)) . $socks_username . pack("C", length($socks_password)) . $socks_password;
$socket->send($packed_cmd);
if (defined $socket->recv($buffer, 1024)) {
#data = unpack("C2", $buffer);
$response{'version'} = $data[0];
$response{'status'} = $data[1];
return 1;
}
} else {
return 1;
}
} else {
&debug(3, $pid, "Cannot authenticate on socks server [$socks_name:$socks_server]\n");
return 0;
}
}
&debug(3, $pid, "Cannot authenticate on socks server [$socks_name:$socks_server]\n");
return 0;
}
If you are okay with IMAP instead of SMTP this might help, but prob not what you're looking for:
sub login() {
## Connect to the IMAP server via SSL
my $socket = IO::Socket::SSL->new(PeerAddr => 'imap.gmail.com',PeerPort => 993);
if(!$socket) {
# handle
}
## Build up a client attached to the SSL socket.
## Login is automatic as usual when we provide User and Password
my $imap = Mail::IMAPClient->new(Socket => $socket,
User => $username,
Password => $password,);
if(!$imap) {
# handle
}
if(!$imap->IsAuthenticated() && ...) {
# handle
}
## good to go
my #folders = $imap->folders();
...
}
Here is my beta code to use SMTP via socks proxy. SSL is working correctly with all servers tested by me. With TLS still have sometimes problems, probably something not according to the RFC.
I want to set timeout in my recv function in this specific code below, because sometimes my script stuck forever. I am new in socket programming so i would really appreciate any help. Thanks in advance.
use IO::Socket::INET;
use IO::Select;
use LWP::UserAgent;
use JSON::XS 'decode_json';
use Data::Dumper;
use DBI();
sub dbconn {
my $db_conf = shift;
my $dbh = DBI->connect("DBI:Pg:dbname=somedatabase;host=somehost", "postgres", "",
{pg_server_prepare =>
0,AutoCommit => 1,RaiseError=>1});
$dbh->do("SET CLIENT_ENCODING TO 'UTF-8';");
return $dbh;
}
# auto-flush on socket
$| = 1;
# creating a listening socket
my $socket = new IO::Socket::INET (
LocalHost => '0.0.0.0',
LocalPort => '5000',
Proto => 'tcp',
Listen => 5,
Reuse => 1
);
die "cannot create socket $!\n" unless $socket;
$sel = IO::Select->new( $socket );
print "Server waiting for client connection on port 5000...\n";
my $command = 1;
my $watchTracker = "*HQ,";
my $tl206 = ",LAT:";
my $watchConnectedCheck = ",A,";
my $gpsType;
my $circleString = ",LINK,";
my $dataToSend;
my $new;
my $dbh = dbconn();
while(#ready = $sel->can_read) {
foreach $fh (#ready) {
if($fh == $socket) {
# Create a new socket
$new = $socket->accept;
$new->recv($dataReceived, 1024);
$new->recv($dataReceived, 1024);
# get information about a newly connected client
my $client_address = $new->peerhost();
my $client_port = $new->peerport();
print "===============================================\n";
print "===============================================\n\n";
print "Connection from $client_address:$client_port\n";
print "General data received: $dataReceived\n\n";
#MORE LINES...
}
else {
# Process socket
# Maybe we have finished with the socket
$sel->remove($fh);
$fh->close;
}
}
}
$dbh->disconnect();
Perhaps I am misunderstanding the question, but have you tried setting a timeout in the socket with "Timeout"?
See IO::Socket::INET.
EDIT: I did not catch the 'recv' bit. You have to use setsockopt, which is not wholly portable, so the final answer is somewhat dependent on your platform. Here are some posts that may help:
How do I set `SO_RCVTIMEO` on a socket in Perl?
http://www.perlmonks.org/?node_id=761935
E.g.,
$socket->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0))
or die "setsockopt: $!";
I'm trying to create a server and client wherein the server returns a diferent message to the client according to what client sends. If the client makes the connection but sends nothing, the server will return message 1 and in case the client sends some data, the server will return message 2. But this doesn't work, the client stays waiting the data and nothing prints.
Client:
use IO::Socket;
my $sock = new IO::Socket::INET (
PeerAddr => '10.1.1.28',
PeerPort => '7070',
Proto => 'tcp' );
if (#ARGV != "") {
print $sock "$ARGV[0] $ARGV[1]";
} else {
$data = <$sock>;
print $data;
}
$sock->close;
Server
use IO::Socket;
my $sock = new IO::Socket::INET (
LocalHost => '10.1.1.28',
LocalPort => '7070',
Proto => 'tcp',
Listen => '1',
);
while(1) {
my $new_sock = $sock->accept();
if (<$new_sock> ne "") {
print $new_sock "conection with parameters";
} else {
print $new_sock "default message";
};
Need to chomp
use IO::Socket;
use Data::Dumper;
my $sock = new IO::Socket::INET(
LocalPort => '7070',
Proto => 'tcp',
Listen => '1',
);
while (1) {
my $new_sock = $sock->accept();
my $in = <$new_sock>;
chomp($in);
if ( $in ne "" ) {
print Dumper($in);
print $new_sock "conection with parameters";
}
else {
print $new_sock "default message";
}
}
I'm trying to connect to some host, using invalid port, and i want to get timeout after X seconds. How to do that ?
My code:
$sock = new IO::Socket::INET(
PeerAddr => $_[0],
PeerPort => $_[1],
Proto => 'tcp',
Timeout => 2
);
If you check the code you'll see (I copied it from my Ubuntu 10.04) :
my $timeout = ${*$sock}{'io_socket_timeout'};
# my $before = time() if $timeout;
undef $#;
if ($sock->connect(pack_sockaddr_in($rport, $raddr))) {
# ${*$sock}{'io_socket_timeout'} = $timeout;
return $sock;
}
return _error($sock, $!, $# || "Timeout")
unless #raddr;
# if ($timeout) {
# my $new_timeout = $timeout - (time() - $before);
# return _error($sock,
# (exists(&Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL),
# "Timeout") if $new_timeout <= 0;
# ${*$sock}{'io_socket_timeout'} = $new_timeout;
# }
Apparently the timeout stuff is commented out so that expleins why it is ignored.
I found a post dating from 2003 where this was discussed. One suggestion (at the bottom) was to open the socket in an eval block which gets terminated by an alarm signal :
eval {
local $SIG{ALRM} = sub { die 'Timed Out'; };
alarm 3;
my $sock = IO::Socket::INET->new(
PeerAddr => inet_ntoa( gethostbyname($host) ),
PeerPort => 'whois',
Proto => 'tcp',
## timeout => ,
);
$sock->autoflush;
print $sock "$qry\015\012";
undef $/; $data = <$sock>; $/ = "\n";
alarm 0;
};
alarm 0; # race condition protection
return "Error: timeout." if ( $# && $# =~ /Timed Out/ );
return "Error: Eval corrupted: $#" if $#;
Not very elegant, but if it works...
Let's verify with a slow server and impatient client :
# Impatient Client
use IO::Socket::INET;
$sock = new IO::Socket::INET(
PeerAddr => "localhost",
PeerPort => "10007",
Proto => 'tcp',
Timeout => 2,
);
print <$sock>;
close($sock);
# SlowServer
use IO::Socket::INET;
$sock = new IO::Socket::INET(
LocalAddr => "localhost",
LocalPort => "10007",
Proto => 'tcp',
Listen => 1,
Reuse => 1,
);
$newsock = $sock->accept();
sleep 5;
#while (<$newsock>) {
# print $_;
#}
print $newsock "Some Stuff";
close($newsock);
close($sock);
if we run this:
pti#pti-laptop:~/playpen$ perl server.pl&
[1] 9130
pti#pti-laptop:~/playpen$ time perl test.pl
Some Stuff[1]+ Done perl server.pl
real 0m5.039s
user 0m0.050s
sys 0m0.030s
So it ignores the 2 second timeout and runs for the full 5 seconds.
Now the other impatient client :
use IO::Socket::INET;
eval {
local $SIG{ALRM} = sub { die 'Timed Out'; };
alarm 2;
$sock = new IO::Socket::INET(
PeerAddr => "localhost",
PeerPort => "10007",
Proto => 'tcp',
Timeout => 2,
);
print <$sock>;
close($sock);
alarm 0;
};
alarm 0; # race condition protection
print "Error: timeout." if ( $# && $# =~ /Timed Out/ );
print "Error: Eval corrupted: $#" if $#;
~
and running it :
pti#pti-laptop:~/playpen$ perl server.pl&
[1] 9175
pti#pti-laptop:~/playpen$ time perl test2.pl
Error: timeout.Error: Eval corrupted: Timed Out at test2.pl line 3.
real 0m2.040s
user 0m0.020s
sys 0m0.010s
Yep, this timeouts after 2 seconds as expected.
So much easier is to use the
IO::Socket::Timeout
as per below and it works like a charm.
use IO::Socket::Timeout;
my $socket = IO::Socket::INET->new( Timeout => 2 );
IO::Socket::Timeout->enable_timeouts_on($socket);
$socket->read_timeout(0.5); # These will work
$socket->write_timeout(0.5); # These will work