Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello, powerfull monks.

I have a problem connecting to a socket.
It's a server program and client. Don't complain on the code, I'm just beginer.

Server prog:

$line = "Hello, world!\n"; $port = 2000; while (getservbyport ($port, "tcp")) { $port++; } ($d1, $d2, $prototype) = getprotobyname ("tcp"); ($d1, $d2, $d3, $d4, $rawserver) = gethostbyname("silver"); $serveraddr = pack ("Sna4x8", 2, $port, $rawserver); socket (SSOCKET, 2, 1, $prototype) || die ("No socket"); bind (SSOCKET, $serveraddr) || die ("Can't bind");<br> listen (SSOCKET, 1) || die ("Can't listen"); ($clientaddr = accept (SOCKET, SSOCKET)) || die ("Can't accept"); select (SOCKET); $| = 1; print SOCKET ("$line\n"); close (SOCKET); close (SSOCKET);
Client prog:

$port = 2000; while (getservbyport ($port, "tcp")) { $port++; } ($d1, $d2, $prototype) = getprotobyname ("tcp"); ($d1, $d2, $d3, $d4, $rawclient) = gethostbyname ("mercury"); ($d1, $d2, $d3, $d4, $rawserver) = gethostbyname ("silver"); $clientaddr = pack ("Sna4x8", 2, 0, $rawclient); $serveraddr = pack ("Sna4x8", 2, $port, $rawserver); socket (SOCKET, 2, 1, $prototype) || die ("No socket"); bind (SOCKET, $clientaddr) || die ("Can't bind"); connect (SOCKET, $serveraddr); $line = <SOCKET>; print ("$line\n"); close (SOCKET);

When I run server then client prog, server waits for client
, but client print the null line.
Can anybody tell me why it can't connect to the server
programe.

Thanks for any help.(I'm just a biginer)
em.

Replies are listed 'Best First'.
Re: problem with SOCKET
by castaway (Parson) on Feb 10, 2003 at 11:10 UTC
    A few ideas: Did you check that the port being used by both programs is the same one after doing the getservbyport loop? (That just looks at the ones with names, and not the ones being used, so I'm not sure its useful anyway.)
    Try leaving the client connected instead of closing after printing the line, and look at the contents of the command 'netstat -an' to see if its connected to the correct port/program ? (netstat -anp on linux, shows which programms are connected to which ports, or get 'Active Ports' from 32bit.bhs.com for Windows)

    I'd advise you to use IO::Socket::INET and IO::Select if you can, programming sockets with those is a whole lot easier than the old c-style.
    An example: Re: Daemons in Perl, and there are probably a lot more examples here somewhere.

    C.

Re: problem with SOCKET
by Starky (Chaplain) on Feb 10, 2003 at 19:06 UTC
    Here is your code in working form:

    Client:

    #!/usr/bin/perl use strict; use Socket; my $port = 2000; my $hostname = 'localhost'; my $protocol = getprotobyname ("tcp"); my $host = gethostbyname ($hostname); my $iaddr = sockaddr_in($port,$host); socket (SOCKET, PF_INET, SOCK_STREAM, $protocol) || die ("Error establ +ishing socket to [$hostname:$port]: $!"); connect (SOCKET, $iaddr); while (defined(my $line = <SOCKET>)) { chomp $line; print "Received from [$hostname:$port]: $line\n"; } close (SOCKET); __END__ Output will look like: [starky@freak bin]$ ./client-test-inet.pl Received from [localhost:2000]: Hello, world! Received from [localhost:2000]: [starky@freak bin]$

    Server:

    #!/usr/bin/perl use strict; use Socket; my $line = "Hello, world!\n"; my $port = 2000; my $protocol = getprotobyname ("tcp"); my $addr = INADDR_ANY; my $clientaddr; my $serveraddr = sockaddr_in($port,$addr); socket (SERVER, PF_INET, SOCK_STREAM, $protocol) || die ("Error establ +ishing socket to port [$port]: $!"); print "Binding to port [$port] ...\n"; bind (SERVER, $serveraddr) || die ("Can't bind: $!"); print "Listening on port [$port] ...\n"; listen (SERVER, SOMAXCONN) || die ("Can't listen: $!"); print "Accepting client connections on port [$port] ...\n"; ($clientaddr = accept (CLIENT, SERVER)) || die ("Can't accept: $!"); my ($clientport,$clientiaddr) = sockaddr_in($clientaddr); my $client = inet_ntoa($clientiaddr); print "Received connection from [$client:$clientport]. Saying hello . +..\n"; print CLIENT "$line\n"; close (CLIENT); close (SERVER); print "Done.\n"; __END__ Output will look like: [starky@freak bin]$ ./server-test.pl Binding to port [2000] ... Listening on port [2000] ... Accepting client connections on port [2000] ... Received connection from [127.0.0.1:55080]. Saying hello ... Done. [starky@freak bin]$

    Some comments:

    • First and foremost: Use strict. If you are a beginner, this one step, which will seem like a pain in the butt now, will pay whatever pains it causes back tenfold. Trust me.
    • Use the Socket module. It provides constants such as PF_INET, SOCK_STREAM, etc. which will make your code both readable and portable.
    • Next, do a perldoc perlipc and memorize it. Or at least work through all the examples. Then read the documentation for IO::Handle, IO::Socket, and IO:Socket::INET. Then read the documentation for Net::Daemon. If you are a beginner, the Net::Daemon module may be a bit to digest, but it really does simplify the process of creating daemons considerably.
    • I don't know quite what you're doing with the while (...) { $port++; }, so I got rid of it.
    • Dispense with manual packing. Use sockaddr_in or a combination of pack_sockaddr_in and unpack_sockaddr_in.
    • You don't need to bind and connect on the client side. Just connect.
    • Note the (more informative) use of $! in the die statements.
    • You don't need to select on the server side. What you're doing is essentially selecting SOCKET as the default filehandle, then explicitly printing to the SOCKET filehandle, a redundant process. Print to the socket filehandle directly and save yourself the select so you can print instructive debugging output to STDOUT or a log file. If you want to make sure output is autoflushed, you can use IO::Socket::INET to generate a $handle (see below), then $handle->autoflush(1).

    In regards to IO::Socket::INET, here is a simplified version of your client (that works just the same):

    #!/usr/bin/perl use strict; use IO::Socket::INET; my ($port,$hostname,$protocol) = (2000,'localhost','tcp'); my $handle = IO::Socket::INET->new( Proto => $protocol, PeerAddr => $hostname, PeerPort => $port ) || die "Cannot connect to host [$hostname] on port [$port]: $!"; while (defined(my $line = <$handle>)) { chomp $line; print "Received from [$hostname:$port]: $line\n"; } $handle->close();
    Hope this helps!