Schrift
[thread]10005[/thread]

win32 udp server

Leser: 1


<< >> 6 Einträge, 1 Seite
hudo
 2007-08-09 04:12
#97810 #97810
User since
2003-11-20
72 Artikel
BenutzerIn
[default_avatar]
Hallo, hab einen UDP server, der requests empfaengt und eine Antwort an den client zurueck schickt,
und einen client der request versendet und eine Antwort empfaengt.

Der client-Code
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/perl
# udp client

use strict;
use Tie::File;
use Socket qw(:DEFAULT :crlf);
$/ = CRLF;
use constant DEFAULT_HOST =>'192.168.178.23';
use constant DEFAULT_PORT =>'4712';
use constant MAX_MSG_LEN => 100;
my $host = shift ||DEFAULT_HOST;
my $port = shift ||DEFAULT_PORT;

my $counter=0;
my @array_file;

my $protocol = getprotobyname('udp');
$port = getservbyname($port, 'udp') unless $port =~ /^\d+$/;

my $data;
my $sendung;

socket(SOCK, AF_INET, SOCK_DGRAM, $protocol) or die "socket() gescheitert: $!";
my $dest_addr = sockaddr_in($port, inet_aton($host));

## Sende-Empfangsschleife ##
while(1) {

fill_with_tie(); ## Sendedaten aus Datei lesen

print "Laenge sendung: length($sendung) \n\n";
if ( length($sendung) == 0 ) {
$sendung = 'init';
} # if
print "sendung: $sendung\n\n";

send(SOCK, $sendung, 0, $dest_addr) or die "send() gescheitert: $!";
recv(SOCK, $data, MAX_MSG_LEN, 0) or die "receive() gescheitert $!";

fill_empfang_file($data); ## Empfang in Datei schreiben

chomp($data);
print "Empfangen: $data \n";

sleep(3);

} # while

sub fill_with_tie {
my $file = "meinfile.txt";
my $line;
my $elem;

$sendung ='';

if ( -e $file ) {
tie @array_file, "Tie::File", $file || die $!;
foreach $elem (@array_file) {
chomp $elem;
$sendung= $sendung ."$elem";
} ## foreach
untie @array_file;
} else {
print "Kann $file nicht oeffnen $!$/";
} ## if -s $file
} ## fill_with_tie #################


sub fill_empfang_file {
my $file="empfangsfile.txt";
my $line = @_[0];
my $elem;

print "Operator: $line \n";
open (EMPFANG, ">>$file") or die "Kann $file nicht oeffnen $!\n";

print EMPFANG "$line\n";
close(FILE);
} ## fill_empfang_file ##############
hudo
 2007-08-09 04:16
#97811 #97811
User since
2003-11-20
72 Artikel
BenutzerIn
[default_avatar]
und hier der server-code
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/perl -w
# udp server
use strict;
use IO::Socket;
use Cwd;
use TIE::File;
### Pfad und Hilfsvariablen intitialisieren
my $aktuellesdir;
my $dirprefix;
#my $dirbin;
my $line; ## Hilfsvariable fuer line
my $quellfile="empfangsfile.txt";
my $EMPFANG;

### UDP Variablen initialisieren
my ($sock, $PORTNO, $MAXLEN, $nachricht);
$PORTNO = 4712;
#$PORTNO = 0;
$MAXLEN = 1024;

my $laenge;
my $startzeit;

$sock = IO::Socket::INET->new ( LocalPort=>$PORTNO, Proto=>'udp')
or die "socket: $@";
print "Warte auf UDP NAchricht auf Port $PORTNO$/";

### Pfade initialisieren
$aktuellesdir=getcwd;
$dirprefix="$aktuellesdir/";

### Datei vorbereiten
my $file = "$dirprefix"."$quellfile";
my @array_quellfile;
my $n_recs_array_quellfile;

if ( -e $file ) {
tie @array_quellfile, "Tie::File", $file || die "cannot open $file $!";
$n_recs_array_quellfile = @array_quellfile;
} else {
system(`touch $file`);
tie @array_quellfile, "Tie::File", $file || die "cannot open $file $!";
$n_recs_array_quellfile = @array_quellfile;
}

while ($sock->recv($nachricht, $MAXLEN)) {
$laenge = length($nachricht);
$startzeit = scalar localtime;

print "Zeitstempel: $startzeit : Laenge: $laenge : Der Client sagte ''$nachricht''$/";
#$sock->send("Zeitstempel: $startzeit : Du sagtest: ''$nachricht'' zu mir $/");
# $sock->send("Zeitstempel: Du sagtest: ''$nachricht'' zu mir $/");

#### print "$startzeit Der Client sagte ''$nachricht''$/";
#### $sock->send("Du sagtest: ''$nachricht'' zu mir $/");
$sock->send("Zeitstempel: ''$startzeit'' : Du sagtest: ''$nachricht'' zu mir $/");
push(@array_quellfile, $nachricht);
} die "recv: $!";
untie @array_quellfile;
hudo
 2007-08-09 04:19
#97812 #97812
User since
2003-11-20
72 Artikel
BenutzerIn
[default_avatar]
Der Server laeuft auf einem XP Rechner mit activestate perl 5.8.8, client auch auf Xp Rechner mit activestate perl 5.8.8
Nun ist es so das man den server zuerst starten muß, ist das normal ?
Desweiteren schickt der client nur ein request und bricht dann mit einer Fehlermeldung (unknown error) bei der recv Zeile ab.

Wenn jedoch im server die zwei Zeilen mit #### davor benutzt werden, statt der jetzigen print und sock->send Zeile,
laeuft der client wie erwartet unendlich, schickt staendig requests und empfaengt sauber.

Was ist da das Problem ?? Wo die Aenderung eigentlich nur einige strings mehr sind ($startzeit, $laenge ) !!

Zur Gegenprobe habe ich auf dem Server-Rechner vmware mit Ubuntu als guest-os installiert und siehe da der client
laeuft unter ubuntu in allen Varianten sauber.

-----------
Sorry wegen der drei Teile, weiss nicht wie man (langes) funktionierendes skript anders einbinden kann.
Man benoetigt noch meinfile.txt mit Request-Inhalt.
Gast Gast
 2007-08-09 21:05
#97861 #97861
hudo+2007-08-09 02:19:49--
[...] Nun ist es so das man den server zuerst starten muß, ist das normal ?


Solange der Server nicht läuft, landet alles, was der Client verschickt, im Datennirvana und der Client wird daraufhin ewig auf die Antwort warten.

Überhaupt solltest Du bei Verwendung von UDP auf jeden Fall mit Timeouts für den Empfang arbeiten, denn das Protokoll garantiert nicht, dass versendete Pakete auch immer ankommen! Mehrere abgeschickte Pakete dürfen bei UDP auch überhaupt nicht, mehrmals oder in durchgewürfelter Reihenfolge ankommen. Die einzige Garantie ist, dass die Daten im Paket intakt sind, sofern es ankommt. In lokalen Netzwerken treten diese Effekte meistens zwar nicht auf, wenn aber eine der bei UDP fehlenden Protokolleigenschaften kritisch ist, sollte man sie auf Applikationsebene implementieren oder gleich TCP verwenden.

Quote
Desweiteren schickt der client nur ein request und bricht dann mit einer Fehlermeldung (unknown error) bei der recv Zeile ab.

Wenn jedoch im server die zwei Zeilen mit #### davor benutzt werden, statt der jetzigen print und sock->send Zeile,
laeuft der client wie erwartet unendlich, schickt staendig requests und empfaengt sauber.

Was ist da das Problem ?? Wo die Aenderung eigentlich nur einige strings mehr sind ($startzeit, $laenge ) !!
[...]


Was bei Deinem Code merkwürdig ist, ist die Tatsache, dass der Server send ohne eine Zieladresse verwendet. Da Du nirgends ein connect ausführst und mit UDP ein verbindungsloses Protokoll verwendest, ist es wohl pure Glückssache, ob das Betriebssystem die Antwort an den richtigen Client verschickt.

Es wäre auch möglich, dass die Daten, die Du verschickst, nicht in ein einzelnes UDP-Paket passen und dann ein Übertragungsfehler entsteht -- die maximale Größe von UDP-Paketen hängt jedenfalls auch vom Betriebssystem ab und die Menge verschickten Textes ist im kommentierten Programmteil ja etwas geringer.
hudo
 2007-08-10 13:38
#97878 #97878
User since
2003-11-20
72 Artikel
BenutzerIn
[default_avatar]
Quote
Überhaupt solltest Du bei Verwendung von UDP auf jeden Fall mit Timeouts für den Empfang arbeiten

Kann mir jemand eine funktionierende Methode fuer den timeout sagen ?
Ich habe mit folgendem code rumexperimentiert, das funktioniert aber nicht sauber
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
## Sende-Empfangsschleife 
while(1) {

fill_with_tie(); ## Sendedaten aus Datei lesen

print "Laenge sendung: length($sendung) \n\n";
if ( length($sendung) == 0 ) {
$sendung = 'init';
} # if
print "sendung: $sendung\n\n";

#Variante 1
#send(SOCK, $sendung, 0, $dest_addr) or die "send() gescheitert: $!\n";

#Variante 2
$sock->send($sendung) or die "sendung gescheitert: $!\n";

#=pod
$startzeit = scalar time();
print "start: $startzeit \n";

$hilfe = $startzeit +3 ;
print "hilfe: $hilfe \n";

$timeout = scalar time();


unless ( $hilfe < $timeout ) {
#sleep(4);
print "in Schleife \n\n";
$timeout = scalar time();
print "timeout:: $timeout \n";
$sock->recv($data, MAX_MSG_LEN) or die "empfang gescheitert $!\n";
# recv(SOCK, $data, MAX_MSG_LEN, 0) or die "receive() gescheitert $!";
}
#=cut


=pod
eval {
local $SIG{ALRM} = sub { die "Timeout\n" };
alarm(TIMEOUT);
$sock->recv($data, MAX_MSG_LEN) or die "empfang gescheitert $!\n";
alarm(0);
};

if ($@) {
die $@ unless $@ eq "Timeout\n";
warn "Timeout !!\n";
} # if
=cut
fill_empfang_file($data); ## Empfang in Datei schreiben
chomp($data);
print "Empfangen: $data \n";
sleep(3);
} # while

Dieser code sollte message verschicken und bis zu einem timeout auf Empfang schalten, danach wieder verschicken, egal ob server lauscht oder nicht.
Quote
Was bei Deinem Code merkwürdig ist, ist die Tatsache, dass der Server send ohne eine Zieladresse verwendet.

Der recv()-Aufruf merkt sich die Quelladresse des zuletzt empfangenen Datagramms, dann benutzt send() daraus die Adresse, ist Eigenheit von IO::Socket.
UDP IST verbindungloses Protokoll.
murphy
 2007-08-10 23:40
#97934 #97934
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
hudo+2007-08-10 11:38:58--
[...] Kann mir jemand eine funktionierende Methode fuer den timeout sagen ?
Ich habe mit folgendem code rumexperimentiert, das funktioniert aber nicht sauber [...]


Wahrscheinlich ist hier der Einsatz des -f select-Systemaufrufes sinnvoll.

Quote
[...] Der recv()-Aufruf merkt sich die Quelladresse des zuletzt empfangenen Datagramms, dann benutzt send() daraus die Adresse, ist Eigenheit von IO::Socket. [...]


Mag sein, allerdings ist das weder in IO::Socket noch in -f send oder -f recv so dokumentiert. Im Gegenteil steht sogar in -f send explizit der Satz "On unconnected sockets you must specify a destination to send TO, in which case it does a C "sendto"". Und ganz nebenbei ist es auch noch unsicher, falls man es mal in einer Multithread- oder Multiprozessumgebung verwendet.

Auch unter C funktioniert manchmal der send-Systemaufruf statt des sendto-Systemaufrufes auf UDP-Sockets. Aber streng nach POSIX-Standard ist das Verhalten hier eben nicht definiert. Gerade wenn das Programm unter mehreren Betriebssystemen laufen soll, würde ich mich lieber nicht auf derart arkane undokumentierte Features verlassen.
When C++ is your hammer, every problem looks like your thumb.
<< >> 6 Einträge, 1 Seite



View all threads created 2007-08-09 04:12.