python(42): socket network programming custom private protocol

1. python network programming

1.socket module

To create a socket, use the socket.socket() function. Its syntax is as follows:

socket.socket(socket_family,socket_type,protocol=0)

socket_family can be the following parameters:

  socket.AF_INET IPv4 (default)

  socket.AF_INET6 IPv6

  socket.AF_UNIX can only be used for inter-process communication on a single Unix system

socket_type can be the following parameters:

  socket.SOCK_STREAM streaming socket, for TCP (default)

  socket.SOCK_DGRAM datagram socket, for UDP

  socket.SOCK_RAW original socket. Ordinary sockets cannot process network messages such as ICMP and IGMP, but SOCK_RAW can. Secondly, SOCK_RAW can also process special IPv4 messages. In addition, using raw sockets, you can pass IP_HDRINCL Socket options are constructed by the user in the IP header.

  socket.SOCK_RDM is a reliable form of UDP, i.e. delivery of datagrams is guaranteed but ordering is not guaranteed. SOCK_RAM is used to provide low-level access to the original protocol and is used when certain special operations need to be performed, such as sending ICMP messages. SOCK_RAM is usually restricted to programs run by power users or administrators.

  socket.SOCK_SEQPACKET Reliable continuous packet service

protocol parameters:

  0 (Default) The protocol associated with a specific address family. If it is 0, the system will automatically select an appropriate protocol based on the address format and socket category.

2. Built-in methods of socket objects

Server-side socket functions

s.bind() binds the address (ip address, port) to the socket. The parameters must be in tuple format. For example: s.bind(('127.0.0.1',8009))

s.listen(5) starts listening, 5 is the maximum number of pending connections

s.accept() passively accepts client connections, blocks, and waits for connections.

Client socket functions

s.connect() connects to the server. The parameters must be in tuple format. For example: s.connect(('127,0.0.1',8009))

Public-purpose socket functions

s.recv(1024) receives TCP data, 1024 is the size of one data reception

s.send(bytes) sends TCP data. The format of data sent by python3 must be in bytes format.

s.sendall() sends the data completely, and the inner loop calls send

s.close() closes the socket

3.demo program

server

#!/usr/bin/env python

# _*_ coding:utf-8 _*_

import socket

import time

IP_PORT = ('127.0.0.1',8009)

BUF_SIZE = 1024

  

tcp_server = socket.socket()

tcp_server.bind(IP_PORT)

tcp_server.listen(5)

  

while True:

    print("waiting for connection...")

    conn,addr = tcp_server.accept()

    print("...connected from:",addr)

    while True:

        data = tcp_server.recv(BUF_SIZE)

        if not data:break

        tcp_server.send('[%s] %s'%(time.ctime(),data))

  

tcp_server.close()

client

#!/usr/bin/env python

# _*_ coding:utf-8 _*_

import socket

  

HOST = '127.0.0.1'

PORT = 8009

BUF_SIZE = 1024

ADDR = (HOST,PORT)

  

client = socket.socket()

client.connect(ADDR)

  

while True:

    data = input(">>> ")

    if not data:break

    client.send(bytes(data,encoding='utf-8'))

    recv_data = client.recv(BUF_SIZE)

    if not recv_data:break

    print(recv_data.decode())

      

client.close()

4. Simple demo of custom protocol

Using a custom protocol to transmit data from Python to Netty - Zhihu

Please refer to the usage of struct library commonly used in network programming.

python(29): struct module_python development notes blog-CSDN blog_python struct module

Reference documentation 

socket — Low-level networking interface — Python 3.10.5 documentation

Detailed explanation of socket module in python-Muzhuang Network Blog

https://www.csdn.net/tags/MtTaMgwsMjc1NzAyLWJsb2cO0O0O.html

network sniffing

https://www.csdn.net/tags/MtTaAg0sNjEzNDQwLWJsb2cO0O0O.html

python network sniffing experiment_moyu learner's blog-CSDN blog_python network sniffing

copy network sniffing code

import socket
import threading
import time
import logging
import struct
import ctypes

activeDegree = dict()
flag = 1

'''
    IP层 协议字段:占8比特。指明IP层所封装的上层协议类型,如ICMP(1)、IGMP(2) 、TCP(6)、UDP(17)
'''

def main():
    global activeDegree
    global glag
    # 获取本机IP地址
    HOST = socket.gethostbyname(socket.gethostname())
    print("HOST: ", HOST)
    # 创建原始套接字,适用于Windows平台
    # 对于其他系统,要把socket.IPPROTO_IP替换为socket.IPPROTO_ICMP
    s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
    s.bind((HOST, 0))
    # s.connect((''))
    # 设置在捕获数据包中含有IP包头
    s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
    # 启用混杂模式,捕获所有数据包
    s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
    # 开始捕获数据包
    while flag:
        data, addr = s.recvfrom(65535)
        mac_len = parse_mac(data)
        ip_len, pro = parse_ip(data)
        if pro == 6:
            parse_tcp(data, ip_len)
        elif pro == 1:
            parse_icmp(data, ip_len)
        # if len(data) - mac_len - ip_len >= 8:
        elif pro == 17:
            parse_udp(data, mac_len + ip_len)
        # print('mac: ', mac)
        # print('get addr', addr)
        host = addr[0]
        activeDegree[host] = activeDegree.get(host, 0) + 1
        # if addr[0] != HOST:
            # print(addr[0])
    # 关闭混杂模式
    s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
    s.close()


def parse_mac(raw_buffer):
    # parse ethernet header
    eth_length = 14

    eth_header = raw_buffer[:eth_length]
    eth = struct.unpack('!6s6sH', eth_header)
    eth_protocol = socket.ntohs(eth[2])
    print('Destination MAC : ' + eth_addr(raw_buffer[0:6]) + \
          ' Source MAC : ' + eth_addr(raw_buffer[6:12]) + ' Protocol : ' + str(eth_protocol))
    # print('P->13/14: '+eth_protocol(raw_buffer[12:14]))

    return eth_length


def eth_addr(a):
    b = "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" % (a[0], a[1], a[2], a[3], a[4], a[5])
    return b


def parse_tcp(raw_buffer, iph_length):
    tcp_header = raw_buffer[iph_length: iph_length + 20]

    tcph = struct.unpack('!HHLLBBHHH', tcp_header)
    source_port = tcph[0]
    dest_port = tcph[1]
    sequence = tcph[2]
    acknowledgement = tcph[3]
    doff_reserved = tcph[4]
    tcph_length = doff_reserved >> 4

    print(('TCP => Source Port: {source_port}, Dest Port: {dest_port}'
           ' Sequence Number: {sequence} Acknowledgement: {acknowledgement}'
           ' TCP header length: {tcph_length}').format(
        source_port=source_port, dest_port=dest_port,
        sequence=sequence, acknowledgement=acknowledgement,
        tcph_length=tcph_length
    ))


def parse_udp(raw_buffer, idx):
    udph_length = 8
    udp_header = raw_buffer[idx: idx + udph_length]

    udph = struct.unpack('!HHHH', udp_header)

    source_port = udph[0]
    dest_port = udph[1]
    length = udph[2]
    checksum = udph[3]

    print(('UDP => Source Port: {source_port}, Dest Port: {dest_port} '
           'Length: {length} CheckSum: {checksum}').format(
        source_port=source_port, dest_port=dest_port,
        length=length, checksum=checksum
    ))


def parse_ip(raw_buffer):
    # IP 头
    ip_header = raw_buffer[0:20]

    # 解析IP头
    # see http://blog.guozengxin.cn/2013/07/25/python-struct-pack-unpack
    iph = struct.unpack('!BBHHHBBH4s4s', ip_header)

    version_ihl = iph[0]
    version = version_ihl >> 4
    ihl = version_ihl & 0xF

    iph_length = ihl * 4

    ttl = iph[5]
    protocol = iph[6]
    s_addr = socket.inet_ntoa(iph[8])
    d_addr = socket.inet_ntoa(iph[9])

    print(('IP -> Version: {version}, Header Length: {header},'
           'TTL: {ttl}, Protocol: {protocol}, Source IP: {source},'
           'Destination IP: {destination}').format(
        version=version, header=iph_length,
        ttl=ttl, protocol=protocol, source=s_addr,
        destination=d_addr
    ))

    return iph_length, protocol


def parse_icmp(raw_buffer, iph_length):
    buf = raw_buffer[iph_length : iph_length + ctypes.sizeof(ICMP)]
    icmp_header = ICMP(buf)

    print(('ICMP -> Type:%d, Code: %d, CheckSum: %d'
                   % (icmp_header.type, icmp_header.code, icmp_header.checksum)))
class ICMP(ctypes.Structure):
    """ICMP 结构体"""
    _fields_ = [
        ('type', ctypes.c_ubyte),
        ('code', ctypes.c_ubyte),
        ('checksum', ctypes.c_ushort),
        ('unused', ctypes.c_ushort),
        ('next_hop_mtu', ctypes.c_ushort)
    ]

    def __new__(self, socket_buffer):
        return self.from_buffer_copy(socket_buffer)

    def __init__(self, socket_buffer):
        pass
t = threading.Thread(target=main)
t.start()
time.sleep(60)
flag = 0
t.join()
for item in activeDegree.items():
    print(item)

strcut, sticky bag phenomenon 

Sticky packet phenomenon in network programming - Zhihu

A brief analysis of the struct module in Python - salted fish mixed with sugar - Blog Garden

Guess you like

Origin blog.csdn.net/qq_37674086/article/details/119561310