Skip to content

Commit 62ec51f

Browse files
author
Roman E. Chechnev
committed
simple UDP|TCP server|client (perl)
1 parent 4deadce commit 62ec51f

File tree

1 file changed

+330
-0
lines changed

1 file changed

+330
-0
lines changed

bin/udp_tcp.pl

+330
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,330 @@
1+
#!/usr/bin/perl
2+
3+
## simple udp|tcp client|server
4+
## Roman E. Chechnev
5+
## https://github.com/m0r1k
6+
7+
use strict;
8+
use warnings;
9+
use IO::Socket::INET;
10+
11+
use constant VERSION => 20241202124027;
12+
13+
sub udp_client()
14+
{
15+
my $host = $ARGV[1];
16+
my $port = $ARGV[2];
17+
my $payload_size = $ARGV[3];
18+
my $ret = -1;
19+
20+
unless (defined $host) {
21+
print("missing argument: 'host'\n");
22+
goto fail;
23+
}
24+
25+
unless (defined $port) {
26+
print("missing argument: 'port'\n");
27+
goto fail;
28+
}
29+
30+
unless (defined $payload_size) {
31+
print("missing argument: 'payload_size'\n");
32+
goto fail;
33+
}
34+
35+
my ($datagram, $flags);
36+
37+
my @symbols = (("0".."9"),("a".."z"),("A".."Z"));
38+
my $symbols_len = scalar(@symbols);
39+
40+
my $data = '';
41+
my $pos = 0;
42+
for (my $i = 0 ; $i < $payload_size; $i++) {
43+
$data .= $symbols[$pos];
44+
$pos++;
45+
if ($symbols_len <= $pos) {
46+
$pos = 0;
47+
}
48+
}
49+
50+
my $sock = IO::Socket::INET->new(
51+
PeerHost => $host,
52+
PeerPort => $port,
53+
Proto => 'udp'
54+
);
55+
56+
my $res = $sock->send($data)
57+
or die("cannot send to socket ($!)");
58+
59+
print("sent $res/$payload_size byte(s)\n");
60+
print("wait answer\n");
61+
62+
$sock->recv($datagram, length($data), $flags);
63+
64+
print "got: " . length($datagram) . " byte(s)\n";
65+
66+
## all ok
67+
$ret = 0;
68+
69+
out:
70+
return $ret;
71+
fail:
72+
$ret = -1;
73+
goto out;
74+
}
75+
76+
sub udp_server()
77+
{
78+
my $host = $ARGV[1];
79+
my $port = $ARGV[2];
80+
my $ret = -1;
81+
82+
if (!$host) {
83+
print("missing argument: 'host'\n");
84+
goto fail;
85+
}
86+
87+
if (!$port) {
88+
print("missing argument: 'port'\n");
89+
goto fail;
90+
}
91+
92+
93+
my $max_len = 65535;
94+
my $sock = IO::Socket::INET->new(
95+
LocalAddr => $host,
96+
LocalPort => $port,
97+
Proto => 'udp'
98+
);
99+
100+
print "listen on $host:$port\n";
101+
102+
my $new_msg = undef;
103+
104+
while ($sock->recv($new_msg, $max_len)) {
105+
my ($port, $ipaddr) = sockaddr_in($sock->peername);
106+
my $peer_addr = inet_ntoa($ipaddr);
107+
my $new_msg_len = length($new_msg);
108+
print("got from: '$peer_addr:$port'"
109+
." $new_msg_len byte(s), send back\n"
110+
);
111+
## send back
112+
my $res = $sock->send($new_msg)
113+
or die("cannot send to socket ($!)\n");
114+
print("sent to '$peer_addr:$port' $res byte(s)\n");
115+
}
116+
117+
## all ok
118+
$ret = 0;
119+
120+
out:
121+
return $ret;
122+
fail:
123+
$ret = -1;
124+
goto out;
125+
}
126+
127+
sub tcp_client()
128+
{
129+
my $host = $ARGV[1];
130+
my $port = $ARGV[2];
131+
my $payload_size = $ARGV[3];
132+
my $ret = -1;
133+
134+
unless (defined $host) {
135+
print("missing argument: 'host'\n");
136+
goto fail;
137+
}
138+
139+
unless (defined $port) {
140+
print("missing argument: 'port'\n");
141+
goto fail;
142+
}
143+
144+
unless (defined $payload_size) {
145+
print("missing argument: 'payload_size'\n");
146+
goto fail;
147+
}
148+
149+
my ($answer, $answer_len, $flags);
150+
151+
my @symbols = (("0".."9"),("a".."z"),("A".."Z"));
152+
my $symbols_len = scalar(@symbols);
153+
154+
my $data = '';
155+
my $pos = 0;
156+
for (my $i = 0 ; $i < $payload_size; $i++) {
157+
$data .= $symbols[$pos];
158+
$pos++;
159+
if ($symbols_len <= $pos) {
160+
$pos = 0;
161+
}
162+
}
163+
164+
my $sock = IO::Socket::INET->new(
165+
PeerHost => $host,
166+
PeerPort => $port,
167+
Proto => 'tcp'
168+
);
169+
170+
unless ($sock) {
171+
print("cannot connect to '$host':'$port'\n");
172+
goto fail;
173+
}
174+
175+
print("connected to '$host':'$port'\n");
176+
print("attempt to send $payload_size byte(s)\n");
177+
178+
my $res = $sock->send($data)
179+
or die("cannot send to socket ($!)\n");
180+
181+
print("send $res byte(s)\n");
182+
183+
$answer_len = 0;
184+
while ($answer_len < $payload_size) {
185+
print("wait data\n");
186+
my ($buff, $buff_len);
187+
$sock->sysread($buff, length($data))
188+
or die("cannot read from socket ($!)\n");
189+
$buff_len = length($buff);
190+
if (0 == $buff_len) {
191+
last;
192+
} elsif (0 > $buff_len) {
193+
print("cannot read from socket\n");
194+
last;
195+
}
196+
$answer .= $buff;
197+
$answer_len += $buff_len;
198+
print("got: $buff_len byte(s),"
199+
. " total got: $answer_len/$payload_size byte(s)"
200+
. "\n"
201+
);
202+
}
203+
204+
print("total got: $answer_len/$payload_size byte(s)\n");
205+
206+
$sock->close();
207+
208+
## all ok
209+
$ret = 0;
210+
211+
out:
212+
if ($sock) {
213+
$sock->close();
214+
}
215+
return $ret;
216+
fail:
217+
$ret = -1;
218+
goto out;
219+
}
220+
221+
sub tcp_server()
222+
{
223+
my $host = $ARGV[1];
224+
my $port = $ARGV[2];
225+
my $ret = -1;
226+
227+
if (!$host) {
228+
print("missing argument: 'host'\n");
229+
goto fail;
230+
}
231+
232+
if (!$port) {
233+
print("missing argument: 'port'\n");
234+
goto fail;
235+
}
236+
237+
my $sock = IO::Socket::INET->new(
238+
LocalAddr => $host,
239+
LocalPort => $port,
240+
Proto => 'tcp',
241+
Listen => 5,
242+
Reuse => 1
243+
);
244+
245+
unless ($sock) {
246+
print "failed bind socket on $host:$port\n";
247+
goto fail;
248+
}
249+
250+
print("listen on $host:$port\n");
251+
252+
while(1) {
253+
my $client_socket = $sock->accept();
254+
unless ($client_socket) {
255+
print("failed accept on $host:$port\n");
256+
goto fail;
257+
}
258+
259+
$client_socket->autoflush(1);
260+
261+
my $client_address = $client_socket->peerhost();
262+
my $client_port = $client_socket->peerport();
263+
my $written_total = 0;
264+
265+
print("client accepted: $client_address:$client_port\n");
266+
267+
while (1) {
268+
my $new_msg;
269+
my $max_len = 65535;
270+
my $was_read = $client_socket->sysread($new_msg, $max_len);
271+
unless($was_read) {
272+
print("client has closed connnection\n");
273+
last;
274+
}
275+
print("got $was_read byte(s)\n");
276+
## send back
277+
my $written = $client_socket->send($new_msg)
278+
or die("cannot send to socket ($!)\n");
279+
280+
$written_total += $written;
281+
print("$written byte(s) sent to socket ($written_total total)\n");
282+
}
283+
$client_socket->close();
284+
}
285+
286+
## all ok
287+
$ret = 0;
288+
289+
out:
290+
if ($sock) {
291+
$sock->close();
292+
}
293+
return $ret;
294+
fail:
295+
$ret = -1;
296+
goto out;
297+
}
298+
299+
sub usage()
300+
{
301+
my @parts = split(/\//, $0);
302+
my $self_name = pop(@parts);
303+
print("Usage $self_name <cmd> args..\n");
304+
print("cmd:\n");
305+
print(" udp_server <host> <port>\n");
306+
print(" udp_client <host> <port> <payload_size>\n");
307+
print(" tcp_server <host> <port>\n");
308+
print(" tcp_client <host> <port> <payload_size>\n");
309+
}
310+
311+
my $type = $ARGV[0] || '';
312+
my $handlers = {
313+
"udp_server" => \&udp_server,
314+
"udp_client" => \&udp_client,
315+
"tcp_server" => \&tcp_server,
316+
"tcp_client" => \&tcp_client
317+
};
318+
my $ret;
319+
320+
my $handler = $handlers->{$type};
321+
if ($handler) {
322+
$ret = $handler->();
323+
} else {
324+
print("unknown type: '$type'\n");
325+
usage();
326+
$ret = -1;
327+
}
328+
329+
exit($ret);
330+

0 commit comments

Comments
 (0)