Re: Socket, Broadcast et fileevent ?



On Mon, 16 Jul 2007 15:43:27 -0700, RV <rvlebars@xxxxxxxxxxx> wrote:

Hello

I spend a lot of time to understand how Sockets work with UDP and
Broadcast, and I think I'm losing myself, so is someone here who could
give me the code to make a program that is an UDP server, listening to
Broadcasted messages. This program has to run on windows XP station,
so, is 'fileevent' possible to use, or multi-threading ?

This program is an emitter too because it has to send UDP brodcasted
messages.

The application of this program is a nine stations on Windows. Each
station must warn other stations when an event occur. I think that UDP
broadcasted is the better solution, but I can make a mistake.

If a solution is better than sockets, I take it, if you have only the
solution on Linux, I take it too, just for understand...

Thanks
RV

Hi, I don't use Windows, but you should be able to get
a bi-directional UDP system going. If you are sending messages
both ways, beware of a lockup condition where both are try
to send or receive at the same time.

As far as fileevent goes, you can replace it with a timer, i.e.
$mw->repeat(10, sub{.....})

For some ideas:
http://perlmonks.org?node_id=553405

http://perlmonks.org?node_id=529812

http://perlmonks.org?node_id=470827


Your best bet is to write it first, as a commandline app,
to avoid the Tk complications. Then add the gui afterwards.

If you want a Quick start to a commandline app, the following is from a
tutorial from Prof. Golden at UNO. It explains it step by step. It's not
UDP, it's TCP, but you are better off with TCP if you need
bi-directional communications.

http://www.cs.uno.edu/~golden/teach.html

I slightly modified the IO-Multiplexed Server so that each client's
message will be echo'd to all. So start the server on one machine,
and start a client on all machines..... the server's only purpose is to
echo the messages to all clients.


First the Client:
#!/usr/bin/perl
##########################################################################
#
# Slightly hacked and heavily documented simple Client example from
# the book Programming Perl, 1st Edition. I don't use the module support
# for sockets much because I want the details to be out in the open
# (primarily so people can take their Perl sockets knowledge and move to
# other languages easily).
#
# Some things are done a little differently than in the server examples
# to give you a little more experience with Perl constructs.
#
# This client accepts input from standard input, sends the input to a
# server, and sends responses from the server to standard output.
#
# Hacking and documentation by Prof. Golden G. Richard III, Dept. of
# Computer Science, University of New Orleans, April 1996-March 1998.
#
# Command line arguments expected are: serverIPaddress, port
#
##########################################################################
#
# Perl socket stuff is based on, and very similar to, C socket stuff.
# The Unix man pages for the various socket system calls such as
# 'listen', 'bind', etc. may be very useful to you. To get
# information on a particular call, such as 'accept', use the following
# command:
#
# % man -s3N accept
#
# The -s3N tells man to look in 3N section of the Unix manual, a section
# that's not searched by default.
#
# Use port addresses in the range 5000-6000 for the assignments.
# If you get an "address already in use" error, try a different port.
#
##########################################################################

# In Perl 5 and above, the Socket module contains Perl definitions for
# the stuff in the C include file "/usr/include/sys/socket.h".
# Rather than manually poking through that include file to get values
# for each architecture, a "use Socket" assures that you'll get the
right
# values. This replaces the following lines in the example in the book:
#
# $AF_INET = 2;
# $SOCK_STREAM = 1;
#
# which turn out to be wrong for Solaris, anyway...
# ($SOCK_STREAM should be 2)

use Socket;

# Sucks in the command line arguments (resident in the array variable
ARGV)
# and assigns them to the variables listed in (). In this case, the
first
# is the IP address of the machine on which the server is
# (hopefully) running. The second is the port on which the server is
# listening.

($them,$port) = @ARGV;

# This checks to see if 'port' has been assigned a value and if it
hasn't,
# assigns the default port value 2345. If 'them' (the machine on which
# the server is running) hasn't been assigned a value, 'localhost' is
# assumed. This means that the server is on the same machine as the
# client (us).

$port = 2345 unless $port;
$them = 'localhost' unless $them;

# This sets up a signal handler to kill the child we'll create later
# in the event that we die

$SIG{'Int'} = 'dokill';

# This is a subprogram that does the killing. The variable $child is
# initially undefined, so we won't try to kill a non-existant child.
# Later it will be the PID of the child we create.

sub dokill {
kill 9, $child if $child;
}

# Strings in back quotes like `ls` run the Unix command inside the
quotes
# and return the output. The hostname command returns the name of the
# machine we're running on. 'chop' removes the newline character in
the
# output from the hostname command.

chop($hostname = `hostname`);

# Looks up important information related to the network protocol you
wish
# to use. 'tcp' is a connection-oriented protocol. Look in
# /etc/protocols for examples of others. Do NOT change this unless you
# know what you're doing.

($name, $aliases, $proto) = getprotobyname('tcp');

# This is a slightly different way of doing the service lookup that was
# done in the Server code. Basically, if the specified port is an
integer,
# the port number lookup isn't done, otherwise it is.

($name, $aliases, $port) = getservbyname($port,'tcp')
unless $port =~ /^\d+$/;

# Let the user know what port we're using and where the server
# is expected to be, just in case (s)he accidentally typed an
# incorrect port or machine name.

print "Using port $port to connect to server on host $them...\n";


# This looks up numeric IP address information corresponding to the
# hostname for the current machine.

($name,$aliases,$type,$len,$thisaddr) = gethostbyname($hostname);

# This looks up numeric IP address information corresponding to the
# hostname where the server is expected to be running.

($name, $aliases,$type,$len,$thataddr) = gethostbyname($them);

# Create one endpoint of the communication link (our end). See the
Server
# code for a more complete explanation of what 'socket' does. If we
# fail to create a socket, 'die' causes execution to terminate and
# display the reason ( stored in $! ) for the failure.

# Remember that AF_INET and SOCK_STREAM are symbols provided by the
# "use Socket;" line. Don't put $ in front of them!!

if (socket(S,AF_INET, SOCK_STREAM, $proto)) {
print "Socket creation succeeded.\n";
}
else {
die $!;
}

# 'bind' connects our socket (just created) to the specified port. As
# in the Server code, the $sockaddr thing is just some magic that allows
# the parameters to 'bind' and (later) 'connect' to be smooshed together
# in the correct way. For most cases this will be "cut and paste" code.
# 'this' gives information about who we are; 'that' refers to the
server.

$sockaddr = 'S n a4 x8';
$this = pack($sockaddr, AF_INET, 0, $thisaddr);
$that = pack($sockaddr, AF_INET, $port, $thataddr);

if (bind(S, $this)) {
print "Bind succeeded.\n";
}
else {
die $!;
}

# This is similar to the 'accept' in the server, except the server is
# waiting for a call and we're actively initiating the conversation.
# 'connect' connects our socket to the server's socket on the other end.

if (connect(S, $that)) {
print "Connect succeeded.\n";
}
else {
die $!;
}

# Force our socket to flush output immediately after a print

select(S);
$| = 1;

# Make standard output the default again

select(STDOUT);

# The interaction we want is to type lines of input and have them echoed
# back by the server. But how can we both wait for input AND be
receptive
# to the server's output? Answer: By forking a process to accept
input
# from standard input (the keyboard) and send it to the server and using
# our current process to receive and display input from the server.

if ($child = fork) {

# We're the parent. Read lines of input from the standard input and
# send them to the server until end of file is seen.

while (<STDIN>) {
print S;
}
# Sleep for 3 seconds then...
sleep 3;

#...then kill ourselves and the child
do dokill();
}
else {
# We're the child. Read lines of input from the server over the
# socket S and output them. Stop if end of file is seen.

while (<S>) {
print "Server: $_";
}
}
__END__


############################################################

Now the Multi-echo server

#!/usr/bin/perl
##########################################################################
#
# I/O Multiplexing Server example.
#
# This server accepts connections from an arbitrary number of clients.
# When a new connection is established, information about the new
connection
# is sent to all connected clients. Input from individual clients is
# simply echoed back to the sender.
#
# Notice that arrays of file handles in Perl are incredibly yucky, since
# file handles aren't first class objects. It's not my fault.
#
# By Prof. Golden G. Richard III, Dept. of Computer Science, University
# of New Orleans, April 1996. Use for any purpose whatsoever granted.
#
# Command line arguments expected are: port
#
##########################################################################
#
# Perl socket stuff is based on, and very similar to, C socket stuff.
# The Unix man pages for the various socket system calls such as
# 'listen', 'bind', etc. may be very useful to you. To get
# information on a particular call, such as 'accept', use the following
# command:
#
# % man -s3N accept
#
# The -s3N tells man to look in 3N section of the Unix manual.
#
# Ranges of port addresses will be assigned to you in class. Generally,
if
# you get an "address already in use" error, try a different port.
# We'll be using ports in the ranges 5000-6000.
#
##########################################################################

# In Perl 5 and above, the Socket module contains Perl definitions for
# the stuff in the C include file "/usr/include/sys/socket.h".
# Rather than manually poking through that include file to get values
# for each architecture, a "use Socket" assures that you'll get the
right
# values. This replaces the following lines in the example in the book:
#
# $AF_INET = 2;
# $SOCK_STREAM = 1;
#
# which turn out to be wrong for Solaris, anyway
# ($SOCK_STREAM should be 2)
#
# In general, hard-coded socket constants in Perl 5+ are a bad practice.
Use
# the Socket module instead.

use Socket;

sub readline {

# 'select'-compatible function for reading one line of input from
# a filehandle.
#
# readline() expects one argument -- filehandle S
#
# sample call: $mystring = readline('S')
#

my $filehandle = $_[0];
my $c='';
my $retstr='';
my $endoffile=0;

while ($c ne "\n" && ! $endoffile) {
if (sysread($filehandle, $c, 1) > 0) {
$retstr = $retstr . $c;
}
else {
$endoffile=1;
}
}

return $retstr;
}

# Sucks in the command line arguments (resident in the array variable
ARGV)
# and assigns them to the variables listed in (). In this case, the
first
# command line argument is the port [more on this later] and it's
# placed into the variable 'port'. We dont care about any other
command-line
# arguments.

($port) = @ARGV;

# This checks to see if 'port' has been assigned a value and if it
hasn't,
# assigns the default port value 2345

$port = 2345 unless $port;

# Looks up important information related to the network protocol you
wish
# to use. 'tcp' is a connection-oriented protocol. Look in
# the file /etc/protocols for examples of others. Don't change this
unless
# you know what you're doing.

($name, $aliases, $protocol) = getprotobyname('tcp');

# In the following, $port is the port the user specified either on the
# command line or by default. =~ is the Perl regular expression
binding
# operator and !~ is the negation of =~. Regular expressions are
# enclosed between / / characters in Perl. \d matches a single digit,
# \d+ matches a string of 1 or more digits, ^ specifies "beginning of
# string", and $ specifies "end of string". /^\d+$/ as a regular
# expression, therefore, matches integers of arbitrary length.
# So... The following line says: If the port contains any non-digit
# characters, look up the port number associated with the symbolic
# name specified by the user. The lookup is done against the
# file/etc/services. Unless you're hacking code to talk to
well-established
# servers such as the httpd daemon, for example, you'll use numeric port
# addresses, so don't worry about this too much.

if ($port !~ /^\d+$/) {
($name, $aliases, $port) = getservbyport($port, 'tcp');
}

# Let the user know what port we're listening on, just in case (s)he
# accidentally typed an incorrect port.

print "Listening on port $port...\n";

# 'socket' creates one endpoint for a communication link (think of it as
# creating a telephone. Later, someone else will create another
telephone
# and wires will be attached between them). The S parameter is the
handle
# associated with the created communication endpoint. AF_INET
specifies
# that we're talking using ports. AF_UNIX would specify that we'd be
# communicating through special files created in the filesystem. This
# is very attractive because then you can do away with the port number
# business, but unfortunately AF_UNIX sockets only work on the same
# machine. SOCK_STREAM sockets communicate using streams of characters.
# Another possibility is unreliable datagram communication using
# SOCK_DGRAM. Just stick with the parameters used here unless you
# know what you're doing.

# In case you're wondering, the AF_INET and SOCK_STREAM symbols are
# provided by the 'use Socket;' statement at the top of the file.
# You do NOT want to put $'s in front of these symbols.

# The 'die' causes execution to terminate with an error message ( which
is
# stored in $_) if the 'socket' call fails. $! is a string describing
# the latest system error message.

socket(S,AF_INET,SOCK_STREAM,$proto) || die "socket : $!";

# so we can restart our server quickly
# The setsockopt function used in the Solution allows you to
# avoid waiting two minutes after killing your server before you
# restart it again (valuable in testing)
# setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1);
setsockopt(S, SOL_SOCKET, SO_REUSEADDR, 1);


# The 'bind' hooks your phone to the port number that was specified.
# Think of all the ports as a telephone switchboard. 'bind' requires
its
# parameters to be in a C structure format. 'pack' smooshes things
# together into a form that 'bind' can stomach. The $sockaddr thing
below
# says "An unsigned short, followed by a short in 'network order',
# followed by a null-padded 4 character string, followed by 8 null
# bytes." It's magic. Don't worry too much about it.

$sockaddr = 'S n a4 x8';
$this = pack($sockaddr, AF_INET, $port, "\0\0\0\0");
bind(S, $this) || die "bind : $!";

# This says "I want 10-way call-waiting." Basically, that you want
# requests to talk to you queued up to a depth of 10.

listen(S, 10) || die "listen: $!";

# Select S temporarily as the default output channel, turn on automatic
# flushing, then select standard output again.

select(S);
$| = 1;
select(STDOUT);

$con = 0;

# Server runs forever, accepting connections from clients

while (1) {

# initialize select bit vectors
$rin = $win = $ein = '';

# If this socket is ready, we have a new connection
vec($rin, fileno(S), 1) = 1;

# ...also want to snoop on existing connections. The check for
# null string is done because we forget about connections by
# zapping the file handle.
foreach (@sockets) {
if ($_ ne "") {
vec($rin, fileno($_), 1) = 1;
}
}

# Wait for some action... the 'select' call will block until one of
# of the sockets whose bit we set above becomes available for
reading.
# A new connection also falls into this category. The undef's are
here
# because we don't care about the output, exceptional conditions,
and
# timeout capabilities of 'select' in this simple example.

print "Waiting...\n";
($numready, $timeleft) = select($rout=$rin, undef, undef, undef);
print "Someone's knocking!!\n";

# Is it a new connection? New connections will cause activity on S

if (vec($rout, fileno(S), 1)) {
# Someone new is ringing...
print "New connection.\n";
# Make a new file handle (yuck). "." concats strings.
$con++;
$sockets[$con - 1] = "NS".$con;

# 'accept' blocks until it notices that an incoming connection
on
# socket S. When this occurs, the incoming connection is
# actually attached to the socket NSn rather than S, thus
leaving
# S free for other incoming connections.
# The value that's returned (in $addr) gives some information
# about the address of the caller.

($addr = accept($sockets[$con - 1], S)) || die $!;

select($sockets[$con - 1]);
$|=1;
select(STDOUT);

# unpack the information returned by 'accept' to get some
# (readable) information about the client we're serving and
# print it to standard output

($af,$port, $inetaddr) = unpack($sockaddr, $addr);
@inetaddr = unpack('C4', $inetaddr);

# tell the other clients who just connected
foreach (@sockets) {
if ($_ ne "") {
print $_
"Got connection $con @ Internet address
@inetaddr\n";
}
}
}

else {
# An existing connection is trying to talk to us...
# just display whatever each waiting client sends
# and then echo the data back to the client. If we receive a
# null length message from a client, wipe out the file handle
# so we don't communicate with that client again.
$sockcount = 0;
foreach (@sockets) {
$sockcount++;
$thesocket = $_;
if (vec($rout, fileno($thesocket), 1)){
# note that data is read with the function 'readline'
# instead of using <$thesocket>; <>-type reading uses
# the buffered I/O library and select doesn't like this
# at all!
$data = &readline($thesocket);
if (! length($data)) {
# 0 length message means "goodbye"
print "Bye to client on socket $thesocket.\n";
close($thesocket);
$sockets[$sockcount-1] = "";
}
else {
print "Received from client $sockcount: $data\n";

#print $thesocket "$data";
foreach my $sck (@sockets){print $sck "client
$sockcount: $data"};

}
}
}
}
}
__END__







--
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html
.



Relevant Pages

  • Re: Socket Exception
    ... In this case the server most likely rejected your ... connection. ... Each command is a new socket connection that is opened and closed ... /// Required designer variable. ...
    (microsoft.public.win32.programmer.networks)
  • Re: ASP.NET 2.0 - a newbie question
    ... Is there some experienced ASP.NET 2.0 developer, ... server that comes bundled Microsoft VWDE. ... A connection attempt failed because the ... connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& ...
    (microsoft.public.dotnet.framework.aspnet)
  • Definition of a socket on Suns website
    ... The page is called "What is a Socket?" ... the server accepts the connection. ... the server gets a new socket bound to a different port. ...
    (comp.lang.java.programmer)
  • Re: problem in accept()
    ... Remember that a socket in the listening state is not ever connected so the ... difference between closing a socket and closing a connection. ... (client IP address, client port number, server IP address, and server port ...
    (microsoft.public.win32.programmer.networks)
  • error when move web service from dev machine to test server
    ... I have a simple web service that I developed on my laptop that resides ... test server, & when I try to run it, I get the error "No connection could be ... No connection could be made because the target machine actively refused it ... Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState ...
    (microsoft.public.dotnet.framework.webservices)