python (42): protocolo privado personalizado de programação de rede de soquete

Primeiro, programação de rede python

1. módulo de soquete

Para criar um soquete, use a função socket.socket(). Sua sintaxe é a seguinte:

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

socket_family pode ter os seguintes parâmetros:

  soquete.AF_INET IPv4 (padrão)

  soquete.AF_INET6 IPv6

  socket.AF_UNIX só pode ser usado para comunicação entre processos em um único sistema Unix

socket_type pode ter os seguintes parâmetros:

  socket.SOCK_STREAM soquete de streaming, para TCP (padrão)

  socket.SOCK_DGRAM soquete de datagrama, para UDP

  socket.SOCK_RAW soquete original. Soquetes comuns não podem processar mensagens de rede como ICMP e IGMP, mas SOCK_RAW pode. Em segundo lugar, SOCK_RAW também pode processar mensagens IPv4 especiais. Além disso, usando soquetes brutos, você pode passar IP_HDRINCL As opções de soquete são construídas pelo usuário no cabeçalho IP.

  socket.SOCK_RDM é uma forma confiável de UDP, ou seja, a entrega de datagramas é garantida, mas o pedido não é garantido. SOCK_RAM é usado para fornecer acesso de baixo nível ao protocolo original e é usado quando certas operações especiais precisam ser executadas, como o envio de mensagens ICMP. SOCK_RAM geralmente é restrito a programas executados por usuários avançados ou administradores.

  socket.SOCK_SEQPACKET Serviço de pacote contínuo confiável

parâmetros de protocolo:

  0 (Padrão)O protocolo associado a uma família de endereços específica. Se for 0, o sistema selecionará automaticamente um protocolo apropriado com base no formato do endereço e na categoria do soquete.

2. Métodos integrados de objetos de soquete

Funções de soquete do lado do servidor

s.bind() vincula o endereço (endereço IP, porta) ao soquete. Os parâmetros devem estar no formato de tupla. Por exemplo: s.bind(('127.0.0.1',8009))

s.listen(5) começa a escutar, 5 é o número máximo de conexões pendentes

s.accept() aceita passivamente conexões de clientes, bloqueia e aguarda conexões.

Funções de soquete do cliente

s.connect() se conecta ao servidor. Os parâmetros devem estar no formato de tupla. Por exemplo: s.connect(('127,0.0.1',8009))

Funções de soquete de uso público

s.recv(1024) recebe dados TCP, 1024 é o tamanho de uma recepção de dados

s.send(bytes) envia dados TCP.O formato dos dados enviados por python3 deve estar no formato bytes.

s.sendall() envia os dados completamente e o loop interno chama send

s.close() fecha o soquete

3. programa de demonstração

servidor

#!/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()

cliente

#!/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. Demonstração simples de protocolo personalizado

Usando um protocolo personalizado para transmitir dados de Python para Netty - Zhihu

Consulte o uso da biblioteca struct comumente usada na programação de rede.

python (29): struct module_python notas de desenvolvimento blog-CSDN blog_python struct module

Documentação de referência 

socket — Interface de rede de baixo nível — Documentação do Python 3.10.5

Explicação detalhada do módulo de soquete no blog da rede python-Muzhuang

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

detecção de rede

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

sniffing de rede python experiment_moyu blog do aluno-CSDN blog_python sniffing de rede

copiar código de detecção de rede

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, fenômeno do saco pegajoso 

Fenômeno de pacotes pegajosos na programação de rede - Zhihu

Uma breve análise do módulo struct em Python - peixe salgado misturado com açúcar - Blog Garden

Acho que você gosta

Origin blog.csdn.net/qq_37674086/article/details/119561310
Recomendado
Clasificación