TCP/IP Programing in Python

Hello,

I am new to TCP/IP. I would like to create simple server and client application in Python. I will be using one computer for TCP/IP server and another computer for TCP/IP client. Both computers are Windows based machines.

The server will request the client to send some known data. The server will receive the data from client and confirm each time.

Do we have any demo project on this which could be helpful in the beginning ?

1 Like

I’d recommend the book Foundations of Python Network Programming, Third Edition by Brandon Rhodes and John Goerzen for general reading on this topic. Here’s some of the basic sample programs:

Here’s the main example of a simple client and server program from the book, saved as udp_local.py:

#!/usr/bin/env python3
# Foundations of Python Network Programming, Third Edition
# https://github.com/brandon-rhodes/fopnp/blob/m/py3/chapter02/udp_local.py
# UDP client and server on localhost

import argparse, socket
from datetime import datetime

MAX_BYTES = 65535

def server(port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind(('127.0.0.1', port))
    print('Listening at {}'.format(sock.getsockname()))
    while True:
        data, address = sock.recvfrom(MAX_BYTES)
        text = data.decode('ascii')
        print('The client at {} says {!r}'.format(address, text))
        text = 'Your data was {} bytes long'.format(len(data))
        data = text.encode('ascii')
        sock.sendto(data, address)

def client(port):
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    text = 'The time is {}'.format(datetime.now())
    data = text.encode('ascii')
    sock.sendto(data, ('127.0.0.1', port))
    print('The OS assigned me the address {}'.format(sock.getsockname()))
    data, address = sock.recvfrom(MAX_BYTES) # Danger!
    text = data.decode('ascii')
    print('The server {} replied {!r}'.format(address, text))

if __name__ == '__main__':
    choices = {'client': client, 'server': server}
    parser = argparse.ArgumentParser(description='Send and receive UDP locally')
    parser.add_argument('role', choices=choices, help='which role to play')
    parser.add_argument('-p', metavar='PORT', type=int, default=1060, help='UDP port (default 1060)')
    args = parser.parse_args()
    function = choices[args.role]
    function(args.p)

You can first run the server with python udp_local.py server and then in another terminal window run the client with python udp_local.py client and watch the two programs communicate over UDP packets. This is a simple setup, and the book has a lot more and is worth the read. You can find copies at your library or online if you don’t want to purchase one.

Hi, I’m not sure if this covers exactly what you’re after, but creating a simple server and client were demonstrated in Charles Severance’s Coursera Course ‘Web Application Technologies and Django’ (https://www.coursera.org/learn/django-database-web-apps/).

You’ll find in Module 1, there are two Video Lectures, (1) Building a Simple Web Browser in Python (2) Building a Simple HTTP Server in Python. And these lectures demo something similar to what you described. You’ll also find the material earlier in the module covers a lot of the foundations of TCP/IP.

Hope this helps, all the best!

Thank you very much for the example. I am wondering if possible to run both server and client on the same machine ? I mean if server and the client both have same IP address. Would it be possible to run ?

Thank you. I have watched some video tutorials on this subject already. Now I am struggling to run the programs in Python. If you can please point me to simple programs for TCP/IP server and client that would be a great help.

Hi, the (1) and (2) lecture videos I referenced earlier provide ‘simple programs’ (including an explainer of the outlined code) that you can use. And yes, these lectures show you how to run both client and server on the same machine, in separate terminals.

Yes, it absolutely is! In fact, there’s a special IP address that you can use on the client to say “the server’s on the same machine as me”: 127.0.0.1 (or ::1).

Thanks for reply. I will have a look and try.

I think it is also possible to check the bandwidth/speed of the established link. I mean if we send/receive packets over TCP/IP between server and client, we can run a program to check the speed, right ?

Ahhh, now you’re getting into a tricky area of definition. You absolutely CAN measure speed by sending packets between server and client; in fact, that’s the ONLY way to measure the actual speed (you might be able to get a nominal speed, but that’s not your true throughput). However…

Measuring throughput requires that you saturate the connection, to the detriment of all else. If anything else is transferring data, your test will show a figure that’s too low. (This is a trap that people sometimes fall into while live-streaming - “my stream’s suffering, maybe I should test the speed RIGHT NOW” and bam, the stream suffers worse.) And to make matters more confusing…

There are lots of different things you can measure, all with slightly different implications. Most people, when they talk about “speed”, are really talking about “throughput”. Let’s say you want to download a 1TB file - how long will that take? Divide 1TB by your throughput rate and that’s how long it’ll take. Similarly, you can measure upload throughput. Great! But…

What about small messages? How long does it take to, say, send out a DNS query and get back a response? This is going to be dominated by latency (ping time), but also can be affected by how you prioritize packets. This doesn’t really affect the measured throughput numbers, but it makes a HUGE difference to how snappy the internet “feels”. Which leads us to the final awkwardness:

People FEEL what happens with small messages, but MEASURE what happens with big transfes. If you and your neighbour have internet connections from competing ISPs, and yours measures 22Mbps while your neighbour’s measures 24Mbps, obviously your neighbour’s is better, right? And so ISPs will tend to configure their networks to favour raw throughput, even at the expense of DNS latency. It’s the difference between having a highway that gets clogged with traffic, and a tram that has a dedicated right-of-way. The highway is moving a lot of cars per hour, and that’s what everyone measures - but the tram will actually get there efficiently.

So, yes, you absolutely can measure the speed. Just be sure what you’re measuring before you start.

How about if there is a dedicated/separate network card (PIC3 to Ethernet RJ45) installed on the computer. And the network card will be only used to connect Ethernet cable to the Microcontroller board. This way we can test the speed that can reach up to maximum link speed, right ?

Throughput will depend on a lot of factors, but it sounds like you should get pretty much the rated speed, yes. Or rather, if you don’t, there would have to be a reason for it.

I found this link to implement TCP IP in Python. The Echo Server and Echo Client programs are mentioned under the link.

https://pymotw.com/2/socket/tcp.html

It says “The client and server should be run in separate terminal windows, so they can communicate with each other.”

Which program to run first ? I guess Echo Server, right ?

Yep. The server needs to be listening first, and then the client can connect to it.

Ah, don’t use that tutorial though, it’s ancient. Find something newer. The socket code won’t be much different, but things like print statements will need to be changed.

Alright. I will find some other code. If you have any suggestion then please share. Thank in advance.

Hello again,

I found the program for server and client.

# Echo Server
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255
s.bind((host, port))

s.listen(5)
socketclient , address = s.accept()
print ("got connection form", address)

con = True
while con:
    msg = socketclient.recv(1024)
    msg = meg.decode("utf-8")
    print (msg)
    if (msg == "quit"):
        con = False
        s.close()
# Echo Client
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255

s.connect(host, port)

con = True
while con:
    msg = input ("enter msg : ")
    s.send (msg.encode("utf-8"))
    if msg == "quit":
        con = False
        s.close()

I run the server programfirst. The following error comes in server terminal. Any idea how to fix that problem ?

Traceback (most recent call last):
  File "D\TCP_IP_Server.py", line 12, in <module>
    s.connect(host, port)
TypeError: socket.connect() takes exactly one argument (2 given)

The same error comes in running client in anohter terminal.

That looks like a typo?

Yeah. Python has chosen to organize socket connections in such a way that you connect to a single destination, regardless of the type of socket you’re connecting to. For TCP sockets, the “destination” is a combination of address and port, given as a tuple. So this results in a slightly odd-looking line of code:

s.connect(host, port) # not this

s.connect((host, port)) # this instead

Note that you do the same thing with binding, which you got correct. It looks odd, but it works.

1 Like

Yes, it works. I fix both errors. Thanks for the help.

I have two questions. The code is working fine without any problem.

print("This is TCP/IP Echo Server")

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255
s.bind((host, port))

s.listen(5)
socketclient, address = s.accept()

print("Got connected form", address)
print("\nListening to TCP/IP Client ... \n")

token = True
while token:
    msg = socketclient.recv(1024)
    msg = msg.decode("utf-8")
    print("TCP/IP Client:", msg)
    if msg == "quit":
        token = False
        s.close()
print("This is TCP/IP Echo Client")

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = socket.gethostname()
port = 1255

s.connect((host, port))

token = True
while token:
    msg = input("Enter message send to TCP/IP Server: ")
    s.send(msg.encode("utf-8"))
    if msg == "quit":
        token = False
        s.close()

Each time the IP address is the same but the “port” number is different and is a random number each time. What is the logic ? The IP address remains the same.

Second question: is there anything wrong in socketclient, address = s.accept() which is used in the server program ?

For the most part, source ports in TCP/IP are randomly assigned from a range and only correspond to the particular instance of the running program, not anything else. They’re used by the OS as a means of associating which incoming packets should have their data forwarded to which program in memory. When your Python client program sends a request to the server, you want the reply to come back to your program, and not your browser or some other application.