python (42): protocole privé personnalisé de programmation réseau socket

1. Programmation réseau Python

1.module de prise

Pour créer un socket, utilisez la fonction socket.socket(). Sa syntaxe est la suivante :

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

socket_family peut être les paramètres suivants :

  socket.AF_INET IPv4 (par défaut)

  socket.AF_INET6 IPv6

  socket.AF_UNIX ne peut être utilisé que pour la communication inter-processus sur un seul système Unix

socket_type peut être les paramètres suivants :

  socket.SOCK_STREAM socket de streaming, pour TCP (par défaut)

  socket.SOCK_DGRAM socket de datagramme, pour UDP

  socket.SOCK_RAW socket brut. Les sockets ordinaires ne peuvent pas traiter les messages réseau tels que ICMP et IGMP, mais SOCK_RAW le peut. Deuxièmement, SOCK_RAW peut également traiter les messages IPv4 spéciaux. De plus, en utilisant les sockets bruts, vous pouvez transmettre IP_HDRINCL Les options de socket sont construites par l'utilisateur dans l'en-tête IP.

  socket.SOCK_RDM est une forme fiable d'UDP, c'est-à-dire que la livraison des datagrammes est garantie mais la commande n'est pas garantie. SOCK_RAM est utilisé pour fournir un accès de bas niveau au protocole d'origine et est utilisé lorsque certaines opérations spéciales doivent être effectuées, telles que l'envoi de messages ICMP. SOCK_RAM est généralement limité aux programmes exécutés par des utilisateurs expérimentés ou des administrateurs.

  socket.SOCK_SEQPACKET Service de paquets continu et fiable

paramètres du protocole :

  0 (par défaut) Le protocole associé à une famille d'adresses spécifique. S'il est 0, le système sélectionnera automatiquement un protocole approprié en fonction du format d'adresse et de la catégorie de socket.

2. Méthodes intégrées des objets socket

Fonctions de socket côté serveur

s.bind() lie l'adresse (adresse IP, port) au socket. Les paramètres doivent être au format tuple. Par exemple : s.bind(('127.0.0.1',8009))

s.listen(5) commence à écouter, 5 est le nombre maximum de connexions en attente

s.accept() accepte passivement les connexions client, bloque et attend les connexions.

Fonctions du socket client

s.connect() se connecte au serveur. Les paramètres doivent être au format tuple. Par exemple : s.connect(('127,0.0.1',8009))

Fonctions de prise à usage public

s.recv(1024) reçoit des données TCP, 1024 est la taille d'une réception de données

s.send(bytes) envoie des données TCP. Le format des données envoyées par python3 doit être au format octets.

s.sendall() envoie les données complètement et la boucle interne appelle send

s.close() ferme le socket

3.programme de démonstration

serveur

#!/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. Démo simple du protocole personnalisé

Utiliser un protocole personnalisé pour transmettre des données de Python à Netty - Zhihu

Veuillez vous référer à l'utilisation de la bibliothèque struct couramment utilisée dans la programmation réseau.

python (29) : notes de développement struct module_python blog-CSDN blog_python struct module

Documentation de référence 

socket — Interface réseau de bas niveau — Documentation Python 3.10.5

Explication détaillée du module socket dans python-Muzhuang Network Blog

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

reniflage de réseau

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

reniflage de réseau python experience_moyu blog de l'apprenant-blog CSDN_reniflage de réseau python

copier le code de détection du réseau

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, phénomène de sac collant 

Phénomène de paquets collants dans la programmation réseau - Zhihu

Une brève analyse du module struct en Python - poisson salé mélangé avec du sucre - Blog Garden

Je suppose que tu aimes

Origine blog.csdn.net/qq_37674086/article/details/119561310
conseillé
Classement