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