For testing purposes I need to create a shell script that connects with a remote IP>Port and sends a simple text TCPIP Socket message.
4 Answers
Using nc (netcat).
Server:
$ nc -l localhost 3000
Client:
$ nc localhost 3000
Both server and client will read and write to standard output/input.
This will work when the server and client are on the same machine. Otherwise, change localhost to the external name of the server. On the server, you may also use 0.0.0.0 (or remove it altogether) to let the server bind to all available interfaces.
Slightly more interesting, a "server" that gives you the time of day if you connect to it and send it a d, and which quits if you send q:
Server (in bash):
#!/bin/bash
coproc nc -l localhost 3000
while read -r cmd; do
case $cmd in
d) date ;;
q) break ;;
*) echo 'What?'
esac
done <&"${COPROC[0]}" >&"${COPROC[1]}"
kill "$COPROC_PID"
Client session:
$ nc localhost 3000 d Thu Jan 12 18:04:21 CET 2017 Hello? What? q
(the server exits after q, but the client doesn't detect that it's gone until you press Enter).
- 320,670
- 36
- 633
- 936
-
2If the server returns a result when client finishes sending data, the `ctrl+c` won't show the result. If using echo, e.g. `echo "cookie" | nc localhost 9090`, the client's output stream will be closed (eof sent) but the client will still wait for the server's result. – AlikElzin-kilaka Jul 17 '18 at 10:38
-
This has got to be one of the most concise and effective client-server examples out there. Thanks! – Pablo Adames Dec 26 '22 at 22:22
-
Replacing localhost for an external host name does not work straight forward, even with the external host being visible to the machine. – Pablo Adames Dec 26 '22 at 22:42
-
To make the communication between machines: remove localhost from the server code and run it on a machine that can be resolved from the one were the client code runs. In the client code change the localhost for the name of the host where the server code is running. – Pablo Adames Dec 26 '22 at 22:51
-
1@PabloAdames This has been made more explicit in the answer now, I hope. – Kusalananda Dec 27 '22 at 00:37
-
@Kusalananda, thanks for improving an already very useful answer! – Pablo Adames Dec 28 '22 at 16:36
In general advice with netcat is better way.
But in bash and ksh you can also do this:
exec 3<>/dev/tcp/hostname/port
echo "request" 1>&3
response="$(cat <&3)"
- 919
- 4
- 10
-
-
in other words, why not just `echo "request" >&3`, I guess the 1 is just redundant – Alexander Mills Apr 20 '18 at 21:55
-
1
try netcat (e.g. nc )
echo GET / HTTP/1.0 | nc 0 80
HTTP/1.1 400 Bad Request
Date: Thu, 12 Jan 2017 13:44:23 GMT
Server: Apache/2.4.18 (Ubuntu)
Content-Length: 311
Connection: close
Content-Type: text/html; charset=iso-8859-1
- in sample above I send a GET (
echo GET / HTTP/1.0) to my local http server - If you don't want complex protocol, this might do the job.
- 31,183
- 18
- 69
- 104
In many cases I have not had access to netcat/socat. I have also had issues with using bash's exec in a distributed computing environment.
Due to its prevalence, an alternative solution is to use GNU AWK's TCP/IP capabilities. It provides a simple syntax based around it's "two-way pipe" operator.
Here is a modified example from this source that will send a TCP message over a socket:
BEGIN {
NetService = "/inet/tcp/0/cs.wisc.edu/finger"
print "coke" |& NetService
close(NetService)
}
The full syntax for the address is: /net-type/protocol/local-port/remote-host/remote-port. When local-port is set to 0 the local host chooses the port automatically which is typically what you want. You can read more about gawk's TCP/IP networking capabilities in the supplied link.
It's worth noting that this can be shortened if you're only going to be sending one message per awk execution:
BEGIN {print "coke" |& "/inet/tcp/0/cs.wisc.edu/finger"}
- 121
- 3