Python Advanced Network Programming

Keywords: Python socket network Linux Windows

Network Communications

Purpose of using the network

Link multiple parties together for data transmission;
Network programming is to allow software on different computers to transfer data, that is, inter-process communication.

ip address

The concept and function of ip address

What is the IP address: some numbers like 192.168.1.1;
ip address: used to identify the only computer in the computer, such as 192.168.1.1; in the local area network is unique.

NIC information

View Network Card Information

Linux: ifconfig
windows: ipconfig

  • ensxx: a network card used to communicate with the outside world;
  • lo: Loop-back network card for local communication;

linux Close/Open Network Card: sudo ifconfig ensxx down/up

Classification of ip and ip addresses

ip is divided into ipv4 and ipv6

The ip address is divided into:

  • Class A address
  • Class B address
  • Class C address
  • Class D address -- for multicast
  • Class E Address - Retained Address, Useless since ipv6 was born
  • Private ip

Unicast - One-to-One
Multicast--One to Many
Broadcasting - many-to-many

port

ip: identification computer;
Port: Identify the process on the computer (running program);
ip and ports are used together to uniquely identify the host application and communicate with the unified software.

Port classification

Well known ports

Fixed the port number assigned to a particular process, which is generally not available to other processes.
Most of the ports less than 1024 are well-known ports.
The range ranges from 0 to 1023.

Dynamic port

Unfixed allocation, dynamic allocation, port number released after use;
Range 1024-65535;

socket

The concept of socket

Socket is a way of inter-process communication, which can realize inter-process communication between different hosts, that is, socket is a necessary thing for network communication.

Create socket

Create sockets:

import socket
soc = socket.socket(AddressFamily, Type)

The function socket.socket creates a socket with two parameters:
Address Family: Optional AF_INET (for internet inter-process communication) and AF_UNIX (for inter-process communication on the same machine);
Type: Socket type, optional SOCK_STREAM (stream socket, mainly for TCP protocol)/SOCK_DGRAM (datagram socket, mainly for UDP socket);

Create tcp sockets

import socket

soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
...
soc.close()

Create udp sockets

import socket

soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
...
soc.close()

udp

udp uses socket to send data

Send messages in the same LAN;
If you use virtual machines and windows, you need to use bridge mode to ensure that in the same LAN;

import socket


def main():
    # Create a udp socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # Using sockets to send and receive data
    udp_socket.sendto(b"hahaha", ("193.168.77.1", 8080))
    # Close
    udp_socket.close()


if __name__ == "__main__":
    main()

Several cases of udp sending data:

  1. Adding b before quotation marks of fixed data can not be used for user-defined data.
  2. User-defined data is sent and encoded using. encode("utf-8").
  3. User circularly sends data
  4. Users can send data circularly and exit

Only the last case, complete code, is posted.

import socket


def main():
    # Create a udp socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    while 1:
        # Get the data to be sent from the keyboard
        send_data = input("Please enter the data you want to send:")
        if send_data == "exit":
            break
        # Using sockets to send and receive data
        udp_socket.sendto(send_data.encode("utf-8"), ("193.168.77.1", 8080))

    # Close
    udp_socket.close()


if __name__ == "__main__":
    main()

udp receives data

The received data is a tuple. The first part of the tuple is the content sent by the sender, and the second part is the ip address and port number of the sender.

import socket


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    localaddr = ('', 8080)
    udp_socket.bind(localaddr)  # You must bind your computer's ip and port

    # receive data
    recv_data = udp_socket.recvfrom(1024)
    # The variable recv_data stores a tuple, such as (b'haha', ('192.168.77.1', 8888)).
    recv_msg = recv_data[0]
    send_addr = recv_data[1]
    # print("%s Sent:%s" % (str(send_addr), recv_msg.decode("utf-8")))  # Data sent by linux is decoded by utf8
    print("%s Sent:%s" % (str(send_addr), recv_msg.decode("gbk")))  # Data sent by windows is decoded by gbk

    udp_socket.close()


if __name__ == "__main__":
    main()

Summary of udp receiving and sending data

The process of sending data:

  1. Create sockets
  2. send data
  3. Close

The process of receiving data:

  1. Create sockets
  2. Binding local own information, ip and port
  3. receive data
  4. Close

Port binding issues

  • If there is no binding port when you send data, the operating system will randomly allocate a port to you, and the same port is used for circular transmission.
  • You can also bind ports before sending data.

Example of udp binding port itself when sending message

import socket


def main():
    # Create a udp socket
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # Binding port
    udp_socket.bind(('192.168.13.1', 8080))
    while 1:
        # Get the data to be sent from the keyboard
        send_data = input("Please enter the data you want to send:")
        if send_data == "exit":
            break
        # Using sockets to send and receive data
        udp_socket.sendto(send_data.encode("utf-8"), ("193.168.77.1", 8080))

    # Close
    udp_socket.close()  # Press ctrl+c to exit


if __name__ == "__main__":
    main()

However, it should be noted that the same port can not be used by two different programs at the same time.

Single, half-duplex, full-duplex

Understanding of Single Work, Half Duplex and Full Duplex

Simplex:
Only one-way transmission of information, others receive, others can not reply to the message, such as broadcasting;

Half duplex:
Both can send messages, but only one person can send messages at the same time, such as a walkie-talkie.

Full duplex:
Both of them can send messages at the same time, such as telephone calls.

udp receives and sends data using the same socket

"""socket Sockets are full duplex"""
import socket


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(('192.168.13.1', 8080))
    # Let the user enter the ip address and port to send
    dest_ip = input("Please enter the data you want to send. ip Address:")
    dest_port = int(input("Please enter the port number of the data you want to send:"))

    # Get the data to be sent from the keyboard
    send_data = input("Please enter the data you want to send:")
    # Using sockets to send and receive data
    udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))
    # Sockets can send and receive data at the same time.
    recv_data = udp_socket.recvfrom(1024)
    print(recv_data)

    # Close
    udp_socket.close()  # Press ctrl+c to exit


if __name__ == "__main__":
    main()

The socket is full duplex, because now the interpreter can only follow the process, step by step, after learning the process thread co-operation can be done.

tcp

tcp-reliable transmission

Mechanism adopted by tcp

  1. Using Send Response Mechanism
  2. Timeout retransmission
  3. Error checking
  4. Flow control and congestion management

The difference between tcp and udp

  1. tcp is safer and more reliable than udp.
  2. Connection oriented
  3. Orderly data transmission
  4. Retransmit lost data
  5. Discard duplicate packets
  6. Error-free data transmission
  7. Blocking/Flow Control

tcp, udp application scenario

tcp application scenario: download, send messages
udp application scenarios: telephone, live video, etc.

tcp client

tcp client sends data

import socket


def main():
    # 1. Create sockets for tcp
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. Link Server
    tcp_socket.connect(('193.168.11.1', 8080))
    # 3. Send/receive messages
    send_data = input("Please enter the message you want to send:")
    tcp_socket.send(send_data.encode("utf-8"))
    # 4. Close sockets
    tcp_socket.close()


if __name__ == "__main__":
    main()

tcp Server

Monitor sockets, specifically for monitoring;
Acept corresponds to a newly created socket. When a request is received by the listener socket, the request is assigned to the new socket, so that the listener socket can continue to listen, and the new socket serves the hook segment.

import socket


def main():
    # Create tcp sockets
    tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    tcp_service_socket.bind(('', 8080))
    # Change the default socket from active to passive
    tcp_service_socket.listen(128)

    # Waiting for Client Links
    new_client_socket, client_addr = tcp_service_socket.accept()
    print("The client address of the link is:", client_addr)
    # Receiving requests from clients
    recv_data = new_client_socket.recvfrom(1024)
    print(recv_data)
    # Send back messages to clients
    new_client_socket.send("hahahah".encode("utf-8"))

    new_client_socket.close()
    tcp_service_socket.close()


if __name__ == '__main__':
    main()

The parameters in listen indicate that only 128 links are allowed at the same time.

Operating Principle of QQ Unbound Port-Extension

udp and tcp are used together.
Using QQ, login first, and then tell Tencent server the port that QQ is running, when sending a message, it forwards it to another QQ through Tencent server.
Unbound ports also have the advantage of allowing multiple QQ Qs to run on a single computer.

The difference between recv and recvfrom

recvfrom contains not only the data sent, but also the information of the people who sent the data.
There's only data in recv.

tcp client server process combing

tcp server process carding

  1. Create server sockets
  2. Binding local information
  3. Change the default socket from active to passive
  4. Waiting for client links, blocking
  5. After being linked by the client, a new customer service socket is created to serve the client.
  6. Receive messages sent by client, blocking
  7. After receiving the message sent by the client, return the message to the client
  8. Close the customer service socket and the server socket

tcp note

  1. tcp servers usually need to be bound, otherwise the client can not find the server.
  2. tcp client is not bound generally, because it is an active link server, so as long as the server's ip, port and other information is determined, the local client can be random.
  3. tcp server can change the active socket created by socket into passive socket through listen, which is what tcp server must do.
  4. When the client needs to link to the server, it needs to use connect to link. udp does not need to link, but sends directly. but tcp must link first, only if the link succeeds can it communicate.

  5. When a tcp client connects to the server, there will be a new socket on the server side. This socket is used to mark the client and serve the client alone.

  6. The socket after liston is a passive socket that receives a link request from a new client, and the new socket returned by accept marks the new client.

  7. Closing the isten socket means that the passive socket is closed, which will cause the new client to be unable to link to the server, but the client that has successfully linked before to communicate normally.

  8. Closing the socket returned by accept means that the client has finished serving.

9. When the client's socket calls close, the server will recv to unblock, and the length of the return is 0, so the server can distinguish whether the client has been offline by the length of the return data.

tcp application case

Example 1 - Handling a business for a user:

"""It can be understood that a customer service in a bank handles business for people in line."""

import socket


def main():
    # 1. Create tcp sockets
    tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. Binding local information
    tcp_service_socket.bind(('', 8080))

    # 3. Change the default socket from active to passive
    tcp_service_socket.listen(128)
    while 1:
        # 4. Waiting for Client Links
        new_client_socket, client_addr = tcp_service_socket.accept()
        print("The client address of the link is:", client_addr)
        # Receiving requests from clients
        recv_data = new_client_socket.recvfrom(1024)
        print(recv_data)
        # Send back messages to clients
        new_client_socket.send("hahahah".encode("utf-8"))
        # Close
        new_client_socket.close()

    tcp_service_socket.close()


if __name__ == '__main__':
    main()

Example 2 - Serve the same user multiple times and determine whether a user has completed the service:

"""It can be understood that a customer service in a bank handles business for people in line."""

import socket


def main():
    # 1. Create tcp sockets
    tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. Binding local information
    tcp_service_socket.bind(('', 8080))

    # 3. Change the default socket from active to passive
    tcp_service_socket.listen(128)
    while 1:
        # 4. Waiting for Client Links
        new_client_socket, client_addr = tcp_service_socket.accept()
        print("The client address of the link is:", client_addr)
        # Cyclic Purpose: Serve the same customer multiple times
        while 1:
            # Receiving requests from clients
            recv_data = new_client_socket.recvfrom(1024)
            print(recv_data)
            # If recv unblock, there are two ways
            # 1. Client sends data.
            # 2. The client calls close
            if recv_data:
                # Send back messages to clients
                new_client_socket.send("hahahah".encode("utf-8"))
            else:
                break
        # Close
        new_client_socket.close()

    tcp_service_socket.close()


if __name__ == '__main__':
    main()

Example 3-tcp file download client and server:

File Download Client

import socket


def main():
    # 1. Create sockets
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. Get the ip, port of the server
    dest_ip = input("Please enter the server you want to link to ip: ")
    dest_port = input("Please enter the port you want to link to:")
    # 3. Link Server
    tcp_socket.connect((dest_ip, dest_port))

    # 4. Get the name of the downloaded file
    want_file = input("Please enter the file you want to download:")
    # 5. Send the file name to the server
    tcp_socket.send(want_file.encode("utf-8"))

    # 6. Receive files to download
    file_data = tcp_socket.recv(1024)
    # 7. Write the data of the received file into a file
    if file_data:
        with open("[Duplicate]" + want_file, "wb") as f:
            f.write(file_data)

    # 8. Close sockets
    tcp_socket.close()
    pass


if __name__ == '__main__':
    main()

File Download Server

import socket


def send_file2client(new_socket, client_addr):
    # 1. Accept the file name sent by the client to download
    want_file = new_socket.recv(1024).decode("utf-8")
    print("Client %s The files to be received are:%s" % (str(client_addr), want_file))
    # 2. Read file data
    file_data = None
    try:
        f = open(want_file, "rb")
        file_data = f.read()
        f.close()
    except Exception as e:
        print("The files you want to download %s Non-existent" % want_file)

    # 3. Send file data to client
    if file_data:
        new_socket.send(file_data)


def main():
    # 1. Create sockets
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. Binding local information
    tcp_socket.bind(('', 8080))
    # 3. Sockets passively accept listen
    tcp_socket.listen(128)
    while 1:
        # 4. Waiting for the client's link accept
        new_socket, client_addr = tcp_socket.accept()
        # 5. Call function to send file to client
        send_file2client(new_socket, client_addr)
        # 7. Close sockets
        new_socket.close()

    tcp_socket.close()


if __name__ == '__main__':
    main()

Posted by seanlim on Tue, 14 May 2019 17:37:12 -0700