J0hnMilt0n

J0hnMilt0n

Reverse Engineer | Android Modder

13 Feb 2022

Socket Programming - Simple Client & Server

Sockets and the socket API are used to send messages across a network.

Let’s focus on building simple echo client and server using TCP socket.

What are TCP Sockets?

TCP(Transmission Control Protocol) is reliable and has in-order data delivery. Here we’re going to create a socket object using socket.socket() and specify the socket type as socket.SOCK_STREAM.

btw, UDP(User Datagram Protocol) sockets created with socket.SOCK_DGRAM aren’t reliable, and data read by the receiver can be out-of-order.

The sequence of socket API calls and data flow for TCP:

tcp data flow

The Server:

  • socket()
  • bind()
  • listen()
  • accept()

server start listening…

The Client:

  • socket()
  • connect()

establish a connection to the server and initiate the three-way handshake.

Create Echo Client & Server

Server

#!/usr/bin/env python3

import socket

HOST = "127.0.0.1"
PORT = 4444 # whatever you want(>1023)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print("Connected by", addr)
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

explanation:

  • with statement helps you close() automatically.
  • AF_INET is the Internet address family for IPv4.
  • SOCK_STREAM is the socket type for TCP.
  • bind() is used to associate the socket with a specific network interface and port number. It expects a 2-tuple like (host, port).
  • listen() enables a server to accept() connections.
  • accept() blocks and waits for an incoming connection. When a client connects, it returns a new socket object.
  • An infinite while loop is used to loop over blocking calls to conn.recv(). And then echoes back using conn.sendall().

Client

#!/usr/bin/env python3

import socket

HOST = "127.0.0.1"
PORT = 4444

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b"Hello friend")
    data = s.recv(1024)

print("Received", repr(data))

run the server and client

$ ./echo-server.py
Connected by ('127.0.0.1', 47060)
-------------------------------------------
it will appear to hang because of accept()
open another terminal
-------------------------------------------
$ ./echo-client.py
Received b'Hello friend'

When server is running…

Use netstat to view socket state:

$ netstat -an | grep 4444
tcp        0      0 127.0.0.1:4444          0.0.0.0:*               LISTEN

Use lsof(list open files) to view state:

$ lsof -i -n
COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
python3 12332 shylock    3u  IPv4 375130      0t0  TCP 127.0.0.1:4444 (LISTEN)

When there’s no listening socket…

  • maybe port number is wrong
  • maybe server isn’t running
  • maybe there’s a firewall
$ ./echo-client.py
Traceback (most recent call last):
  File "./echo-client.py", line 9, in <module>
    s.connect((HOST, PORT))
ConnectionRefusedError: [Errno 111] Connection refused

Why 127.0.0.1? What’s the loopback interface?

The loopback interface is contained inside the host. When you’re using it, data never leaves the host. The loopback interface and IP address 127.0.0.1 or ::1 referred to as “localhost”.

ref:

Categories

Tags