Socket client/server example not working on Windows 2K 
Author Message
 Socket client/server example not working on Windows 2K

I prepared a short pair of prototype socket client-server
programs, planning to expand them into what is required
for a project I am engaged on at work.

Initially, to test the mechanism, the client just prompts for
a text line, sents it to the server, which displays it and
returns a reply.

On Unix (SunOS) everything works fine with one or more clients
each with a TCP socket connection to the server at once, which
is the intention.

On Windows 2K (using ActiveState Perl v5.6.1 build 631,
MSWin32-x86-multi-thread) the pair work fine with a single
client; but if _two_ clients are started then the server
displays all output from the first client immediately,
but buffers all output for the second client (and only
displays this when the first client disconnects).

These symptoms may be enough for a guru to know what is
going on. But in case not, or anyone spots any obvious
howlers, or risky /sub-optimal features, in my code this
follows below. (It isn't too long.)

(and yes, I have studied the 'perlipc' man page as best
I can..)

Anyway, I'd be grateful if anyone finds time to to help.

Cheers


SERVER:

   use strict;

   use Socket;

   use FileHandle;

   use vars qw
   {
     $wdlog
     $wdport
   };

sub logmsg
{
   my $text = shift;

   open LOG, '>>', $wdlog
     or die "open ('$wdlog', '>>') failed: $!";

   print LOG "$text\n";

   close LOG
     or die "open ('$wdlog', '>>') failed: $!";

Quote:
}

   STDOUT-> autoflush (1);

   $wdlog = "fred.log";

   $wdport = 9002;                  # hard-coded for now

   my $proto = getprotobyname ('tcp');

   socket (SOCKGEN, PF_INET, SOCK_STREAM, $proto)
     or die "socket: $!";

   setsockopt (SOCKGEN, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) # 'l' is "ell"
     or die "setsockopt: $!";

   bind (SOCKGEN, sockaddr_in ($wdport, INADDR_ANY))  
     or die "bind: $!";

   listen (SOCKGEN, SOMAXCONN)
     or die "listen: $!";

  # multi-threaded server forks off a child version for each incoming request.
  #
   my $paddr;

   my $waitedpid = 0;

   sub REAPER
   {
      $waitedpid = wait;

     # The following line reinstates the signal handler. This is not
     # needed for BSD and POSIX Unix, but may be needed for SysV Unix.
     #
      $SIG{CHLD} = \&REAPER;    # if sigaction(2) is not available
   }

   $SIG{CHLD} = \&REAPER;

  # We assume we are running on a system with non-restartable system
  # calls, and in this case we must use a for-loop that seems slightly
  # more elaborate than necessary, because the act of collecting the
  # zombie child process may cause the accept() call to abort and
  # return _undef_, which in turn aborts the for-loop.
  #
   my $sockclt;

   for ( $waitedpid = 0;
          ($paddr = accept ($sockclt, SOCKGEN)) or $waitedpid;
            $waitedpid = 0, close $sockclt)
   {
      next if $waitedpid and not $paddr;    # or check $! == EINTR

      my ($cl_port, $iaddr) = sockaddr_in ($paddr);

      my $cl_name = gethostbyaddr ($iaddr, AF_INET);

      my $cl_host = inet_ntoa ($iaddr);

      my $client  = "$cl_name [$cl_host] : $cl_port";

      logmsg "connection from $client";

      my $pid = undef;

      if (!defined ($pid = fork))
      {
         logmsg  "cannot fork: $!";

         close $sockclt;
      }

      elsif ($pid)      # in parent
      {

         logmsg "begat $pid";
      }

      else              # in child
      {
         binmode $sockclt;

         $sockclt->autoflush (1);

         print "$client connected\n";

         my $line = '';

         while (defined ($line = <$sockclt>))
         {
            chomp $line;

            print "$client sent '$line'\n";

            print $sockclt "got '$line'\n";
         }

         print "$client disconnected\n";

         close $sockclt;

         exit;
      }
   }

CLIENT:

   use strict;

   use Socket;

   use FileHandle;

   use vars qw
   {
     $wdlog
     $wdport
   };

   my $naddr = 'localhost';

   my $iaddr = gethostbyname ($naddr)
     or die "gethostbyname ('$naddr') failed: $!";

   my $nproto = 'tcp';

   my $iproto = getprotobyname ($nproto)
     or die "getprotobyname ('$nproto') failed: $!";

   $wdport  = 9002;   # hard-coded for now

   if ($wdport =~ /\D/)  # first character not a digit, e.g. 'watchdog'
   {
      $wdport  =  getservbyname ($wdport, $nproto)
        or die "getservbyname ('$wdport', '$nproto') failed: $!";
   }

   my $paddr = sockaddr_in ($wdport, $iaddr);

   socket (SOCKET, PF_INET, SOCK_STREAM, $iproto)
     or die "socket: $!";

   connect (SOCKET, $paddr)
     or die "connect: $!";

   binmode SOCKET;

   SOCKET->autoflush (1);

   my $line;

   while (1)

   {
      print "type a line: ";

      $line = <STDIN>;

      chomp $line;

      last if ($line =~ /[QqXx]/);

      print "sending server '$line'\n";

      print SOCKET "$line\n";

      $line = <SOCKET>;

      chomp $line;

      print "server replied: '$line'\n";
   }

   close SOCKET
     or die "close (socket) failed: $!";

   exit;



Sat, 30 Apr 2005 20:23:27 GMT  
 Socket client/server example not working on Windows 2K

Quote:
> I prepared a short pair of prototype socket client-server
> programs, planning to expand them into what is required
> for a project I am engaged on at work.

> On Unix (SunOS) everything works fine with one or more clients
> each with a TCP socket connection to the server at once, which
> is the intention.

> On Windows 2K (using ActiveState Perl v5.6.1 build 631,
> MSWin32-x86-multi-thread) the pair work fine with a single
> client; but if _two_ clients are started then the server
> displays all output from the first client immediately,
> but buffers all output for the second client (and only
> displays this when the first client disconnects).

Unless this is an exercise to learn BSD sockets, consider using
IO::Socket::INET to build them rather than the low-level calls.

What status messages does the server print when the second client
connects?  Tracing through them might help determine the problem.

If fork() is misbehaving under MSWin32-- and it may be, because fork()
is implemented with threads on that platform-- consider using
IO::Select to multiplex the connections in a single process.

IO::Socket::INET and IO::Select are standard modules that come with
Perl.




Sun, 01 May 2005 17:06:47 GMT  
 Socket client/server example not working on Windows 2K

Quote:


> > I prepared a short pair of prototype socket client-server
> > programs, planning to expand them into what is required
> > for a project I am engaged on at work.

> > On Unix (SunOS) everything works fine with one or more clients
> > each with a TCP socket connection to the server at once, which
> > is the intention.

> > On Windows 2K (using ActiveState Perl v5.6.1 build 631,
> > MSWin32-x86-multi-thread) the pair work fine with a single
> > client; but if _two_ clients are started then the server
> > displays all output from the first client immediately,
> > but buffers all output for the second client (and only
> > displays this when the first client disconnects).

> Unless this is an exercise to learn BSD sockets, consider using
> IO::Socket::INET to build them rather than the low-level calls.

Many thanks for your reply, Rocco. I only wish I could use IO::Socket.
But the snag is the server will be receiving a constant stream of event
messages from various clients and has to store these in a different
MySQL database for each. So if everything had to run explicitly in
one process, my server code would be constantly disconnecting from
one database and connecting to another.

(Of course, if there is a nifty way of calling DBI::connect on more
than one database, and switching quickly between them, then this
would avoid the problem. Perhaps one can call DBI::connect on some
database, and then just execute 'use <database>'; statements to
switch databases thereafter. Anyway, I won't speculate further here,
as SQL is off-topic for Perl.)

Quote:
> What status messages does the server print when the second client
> connects?  Tracing through them might help determine the problem.

I did manage to eliminate the output buffering problem on Windows
by replacing every read() and write() socket call by sysread() and
syswrite() resp.

Works fine with one client, then two, then more. _But_ as soon as
a client disconnects (even with the $SIG{CHLD} assignment commented
out in the server code), the server bombs out with a message window
comprising:

  perl.exe has generated errors and will be closed by Windows.

  An error log is being created

which is a fat lot of use, as it doesn't give any the name or
location of the error log (and I couldn't find any file called
*.log or *.err anywhere in the Perl directory tree). Does anyone
know where this error log goes?

Anyway, I then upgraded from ActiveState perl v5.6.1 to v5.8.0
(beta), hoping that all these problems would go away. But now
things are much _worse_, as the server bombs out with the above
message as soon as the first client tries to connect!

Looks like the signal handling, newly introduced in 5.8.0 as the
readme file says, has gone pear-shaped!

Quote:
> If fork() is misbehaving under MSWin32-- and it may be, because
> fork() is implemented with threads on that platform-- consider
> using IO::Select to multiplex the connections in a single process.

I really wish the judge in the recent Microsoft anti-trust case
had included in the settlement conditions a caveat that all Windows
versions must incorporate a kosher, copy-on-write fork() call, to be
made publicly available on free upgrade packs within, say, six months.

If not then he/she missed a major trick, as the absence of a fork()
causes huge problems for all kinds of Unix-to-Windows ports, not just
Perl, and its continuing absence seems to me like a clear-cut example
of Microsoft's obstructive tactics that the court case was all about.

Cheers




Tue, 03 May 2005 13:19:57 GMT  
 Socket client/server example not working on Windows 2K

Quote:



> > > I prepared a short pair of prototype socket client-server
> > > programs, planning to expand them into what is required
> > > for a project I am engaged on at work.

> > > On Unix (SunOS) everything works fine with one or more clients
> > > each with a TCP socket connection to the server at once, which
> > > is the intention.

> > > On Windows 2K (using ActiveState Perl v5.6.1 build 631,
> > > MSWin32-x86-multi-thread) the pair work fine with a single
> > > client; but if _two_ clients are started then the server
> > > displays all output from the first client immediately,
> > > but buffers all output for the second client (and only
> > > displays this when the first client disconnects).

> > Unless this is an exercise to learn BSD sockets, consider using
> > IO::Socket::INET to build them rather than the low-level calls.

> Many thanks for your reply, Rocco. I only wish I could use IO::Socket.
> But the snag is the server will be receiving a constant stream of
> event messages from various clients and has to store these in a
> different MySQL database for each. So if everything had to run
> explicitly in one process, my server code would be constantly
> disconnecting from one database and connecting to another.

Err, why?  You can have more than one database connection open in a perl
process.

Quote:
> (Of course, if there is a nifty way of calling DBI::connect on more
> than one database, and switching quickly between them, then this
> would avoid the problem.

Yes, you make one database handle for each database, and switch between
handles as needed.

Quote:
> Perhaps one can call DBI::connect on some database, and then just
> execute 'use <database>'; statements to switch databases thereafter.

No, you call DBI->connect for *each* database, and store the handle
somewhere.

Quote:
> Anyway, I won't speculate further here, as SQL is off-topic for Perl.)

It's not a matter of SQL, but a matter of using the DBI.  Which makes it
on-topic for Perl.

- Show quoted text -

Quote:
> > What status messages does the server print when the second client
> > connects?  Tracing through them might help determine the problem.

> I did manage to eliminate the output buffering problem on Windows
> by replacing every read() and write() socket call by sysread() and
> syswrite() resp.

> Works fine with one client, then two, then more. _But_ as soon as
> a client disconnects (even with the $SIG{CHLD} assignment commented
> out in the server code), the server bombs out with a message window
> comprising:

>   perl.exe has generated errors and will be closed by Windows.

>   An error log is being created

> which is a fat lot of use, as it doesn't give any the name or
> location of the error log (and I couldn't find any file called
> *.log or *.err anywhere in the Perl directory tree). Does anyone
> know where this error log goes?

Well, if you were using unix, the file would be called "core".

But even so, this would be a binary file, and not useful unless you have
a C de{*filter*}, such as gdb.

Quote:
> Anyway, I then upgraded from ActiveState perl v5.6.1 to v5.8.0
> (beta), hoping that all these problems would go away. But now
> things are much _worse_, as the server bombs out with the above
> message as soon as the first client tries to connect!

> Looks like the signal handling, newly introduced in 5.8.0 as the
> readme file says, has gone pear-shaped!

Signal handling has been around for much longer than that... but it was
altered in 5.8.0 so that fewer segmentation faults, etc, could occur.

Quote:
> > If fork() is misbehaving under MSWin32-- and it may be, because
> > fork() is implemented with threads on that platform-- consider
> > using IO::Select to multiplex the connections in a single process.

> I really wish the judge in the recent Microsoft anti-trust case
> had included in the settlement conditions a caveat that all Windows
> versions must incorporate a kosher, copy-on-write fork() call, to be
> made publicly available on free upgrade packs within, say, six months.

Windows doesn't include *any* kind of fork.  Perl uses threads to fake
it.

Quote:
> If not then he/she missed a major trick, as the absence of a fork()
> causes huge problems for all kinds of Unix-to-Windows ports, not just
> Perl, and its continuing absence seems to me like a clear-cut example
> of Microsoft's obstructive tactics that the court case was all about.

On unix, fork is generally used for two things -- starting new,
seperate, process (usually done as fork then exec), and for having one
program do two things at once (fork, and use pipes for the child and
parent to communicate).

On windows, you can use OpenProcess for the first, and threads and
windows messages for the second, and it works mostly ok -- it's just a
different way of doing things.

You don't *need* fork semantics to do the things that one uses fork for
on unix.  It's when you're trying to design something which works on
both systems that you end up whining about fork being missing on
windows.

--
my $n = 2; print +(split //, 'e,4c3H r ktulrnsJ2tPaeh'
."\n1oa! er")[map $n = ($n * 24 + 30) % 31, (42) x 26]



Tue, 03 May 2005 21:45:11 GMT  
 Socket client/server example not working on Windows 2K

Quote:


>> > I prepared a short pair of prototype socket client-server
>> > programs, planning to expand them into what is required
>> > for a project I am engaged on at work.

>> > On Unix (SunOS) everything works fine with one or more clients
>> > each with a TCP socket connection to the server at once, which
>> > is the intention.

>> > On Windows 2K (using ActiveState Perl v5.6.1 build 631,
>> > MSWin32-x86-multi-thread) the pair work fine with a single
>> > client; but if _two_ clients are started then the server
>> > displays all output from the first client immediately,
>> > but buffers all output for the second client (and only
>> > displays this when the first client disconnects).

>> Unless this is an exercise to learn BSD sockets, consider using
>> IO::Socket::INET to build them rather than the low-level calls.

> Many thanks for your reply, Rocco. I only wish I could use IO::Socket.
> But the snag is the server will be receiving a constant stream of event
> messages from various clients and has to store these in a different
> MySQL database for each. So if everything had to run explicitly in
> one process, my server code would be constantly disconnecting from
> one database and connecting to another.

This doesn't follow, though.  You can use IO::Socket::INET to replace
the low-level socket() calls you're currently using.  That will
simplify your code and possibly flush out the fork() problem you're
having.  At the very least, there will be less code for you to debug
and maintain, which will help you focus on the problem at hand: that
fork() may be misbehaving on MSWin32.

IO::Socket::INET does not preclude fork().  In fact, the two work fine
together.

Quote:
> (Of course, if there is a nifty way of calling DBI::connect on more
> than one database, and switching quickly between them, then this
> would avoid the problem. Perhaps one can call DBI::connect on some
> database, and then just execute 'use <database>'; statements to
> switch databases thereafter. Anyway, I won't speculate further here,
> as SQL is off-topic for Perl.)

Generally speaking, one forks off a pool of DBI connections and passes
requests to idle ones.  They perform the slow task of... well,
whatever you tell them to... off in other processes, so things run
concurrently and much faster.

The method works beautifully on Unix systems.  Too bad this is fraught
with trouble on Windows, or it would be ideal.

- Show quoted text -

Quote:
>> What status messages does the server print when the second client
>> connects?  Tracing through them might help determine the problem.

> I did manage to eliminate the output buffering problem on Windows
> by replacing every read() and write() socket call by sysread() and
> syswrite() resp.

> Works fine with one client, then two, then more. _But_ as soon as
> a client disconnects (even with the $SIG{CHLD} assignment commented
> out in the server code), the server bombs out with a message window
> comprising:

>   perl.exe has generated errors and will be closed by Windows.

>   An error log is being created

> which is a fat lot of use, as it doesn't give any the name or
> location of the error log (and I couldn't find any file called
> *.log or *.err anywhere in the Perl directory tree). Does anyone
> know where this error log goes?

> Anyway, I then upgraded from ActiveState perl v5.6.1 to v5.8.0
> (beta), hoping that all these problems would go away. But now
> things are much _worse_, as the server bombs out with the above
> message as soon as the first client tries to connect!

> Looks like the signal handling, newly introduced in 5.8.0 as the
> readme file says, has gone pear-shaped!

Well, it *is* a beta.  You should see things working much nicer later
on when the bugs are worked out.  Meanwhile, report the problem so the
ActiveState people know what to fix.  Otherwise it may never get
resolved.

Quote:
> I really wish the judge in the recent Microsoft anti-trust case
> had included in the settlement conditions a caveat that all Windows
> versions must incorporate a kosher, copy-on-write fork() call, to be
> made publicly available on free upgrade packs within, say, six months.

> If not then he/she missed a major trick, as the absence of a fork()
> causes huge problems for all kinds of Unix-to-Windows ports, not just
> Perl, and its continuing absence seems to me like a clear-cut example
> of Microsoft's obstructive tactics that the court case was all about.

Have you tried Perl 5.8's threads, though?  Those should be about as
heavyweight (they use the same method that fork() emulation does), but
they may work better because they don't pretend they're something
they're not.




Wed, 04 May 2005 03:51:33 GMT  
 Socket client/server example not working on Windows 2K
[snip]

Quote:
> Generally speaking, one forks off a pool of DBI connections and passes
> requests to idle ones.  They perform the slow task of... well,
> whatever you tell them to... off in other processes, so things run
> concurrently and much faster.

> The method works beautifully on Unix systems.  Too bad this is fraught
> with trouble on Windows, or it would be ideal.

It can be done on windows without *too* much problem, but you can't
simply use fork() for starting each process in the pool -- you have to
use IPC::Open2.

--
my $n = 2; print +(split //, 'e,4c3H r ktulrnsJ2tPaeh'
."\n1oa! er")[map $n = ($n * 24 + 30) % 31, (42) x 26]



Wed, 04 May 2005 08:37:47 GMT  
 Socket client/server example not working on Windows 2K

Quote:


> > [...]

> > Many thanks for your reply, Rocco. I only wish I could use IO::Socket.
> > But the snag is the server will be receiving a constant stream of
> > event messages from various clients and has to store these in a
> > different MySQL database for each. So if everything had to run
> > explicitly in one process, my server code would be constantly
> > disconnecting from one database and connecting to another.

> Err, why?  You can have more than one database connection open in
> a perl process.

Doh! Yes, that was the missing piece of the jigsaw. I've now recoded
the server and the client both to use IO::Select and IO::Socket and
both work fine on Windows and Unix. Thanks for the help everyone.


Wed, 11 May 2005 13:48:36 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. perl book socket server example does not work

2. IO::Socket - The server will not reply back to the client

3. Client socket app not reading from server.

4. server example does not work on IRIX 5.3

5. Send mail script not working in 2nd server but working in 1st server

6. Unlink Not Working On Windows Server

7. Send mail script not working in 2nd server but working in 1st server

8. backticks not working fine on Perl 5 - Windows NT 4.0 peer web server

9. setting up a socket server client and server.....?

10. simple socket client-server interaction works on C, but the analogous code does not work with Perl

11. Wanted: UDP client/server example

12. Wanted: example of UDP client/server

 

 
Powered by phpBB® Forum Software