Python脚本发送接收组播报文

组播发送脚本

python send_mcast.py  -g 232.1.2.3 -p 12345

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket
import struct
import os
import argparse
import logging

# 组播组地址,范围是224.0.0.0 - 239.255.255.255,这里选用224.0.0.1作为示例
multicast_group = '232.1.2.3'
# 组播端口号,可自行按需选择合适的值,这里用12345
multicast_port = 12345
# 要发送的消息内容
message = "Hello, this is a multicast message example"

filename = "test.txt"
filename = "send_mcast.py"

# 创建命令行参数解析器
parser = argparse.ArgumentParser(description='组播消息接收程序')
# 组播组地址参数,默认值设为示例中的232.1.2.3,可通过命令行修改
parser.add_argument('-g', '--group', type=str, default='232.1.2.3', help='组播组地址')
# 组播端口号参数,默认值设为示例中的12345,可通过命令行修改
parser.add_argument('-p', '--port', type=int, default=12345, help='组播端口号')
#localaddress
#input file
parser.add_argument('-f', '--infile', type=str, default="", help='发送文件')
args = parser.parse_args()

multicast_group = args.group
multicast_port = int(args.port)
filename=args.infile if args.infile else filename


# TTL值,可根据实际需求调整,范围通常是1 - 255,这里设置为10
ttl_value = 10

# 创建UDP套接字
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 设置套接字选项,允许重用地址
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

# 设置IP数据报的TTL值,IPPROTO_IP表示IP协议层,IP_MULTICAST_TTL是设置TTL的选项
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl_value)

#don't need to join group on sender
# 将套接字绑定到本地所有可用地址(用空字符串表示)和指定的组播端口
#sock.bind(('', multicast_port))

# 加入组播组
local_addr = socket.inet_aton('192.169.1.2')
group = socket.inet_aton(multicast_group)

mreq = struct.pack('4sL', group, socket.INADDR_ANY)
#mreq = struct.pack('4s4s', group, local_addr)

#sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)

# 发送组播消息,需将消息编码为字节类型,因为网络传输的数据是字节流形式
#sock.sendto(message.encode('utf-8'), (multicast_group, multicast_port))
# 获取文件大小,用于后续判断是否发送完成
file_size = os.path.getsize(filename)
sent_size = 0

# 以二进制模式打开文件,方便处理各种类型的文件
with open(filename, 'rb') as file:
    while True:
        # 每次读取1024字节的数据块,可根据实际网络情况和文件大小调整这个值
        data = file.read(1472)
        if not data:
            break
        # 发送组播消息,需将消息编码为字节类型,因为网络传输的数据是字节流形式
        sock.sendto(data, (multicast_group, multicast_port))
        sent_size += len(data)
        print("发送 {} 字节, 已发送 {} 字节,共 {} 字节".format(len(data), sent_size, file_size))

end_marker = "END".encode('utf-8')
sock.sendto(end_marker, (multicast_group, multicast_port))
print("发送结束标志,发送结束")

# 关闭套接字
sock.close()

组播接收脚本

#python mcast_receiver.py -g 232.1.2.3 -p 12345 -i 20.0.0.2 -o /tmp/rec.log

#!/usr/bin/python
# -*- coding: utf-8 -*-

import argparse
import socket
import struct
import logging

# 配置日志记录基本设置,设置日志级别为INFO,日志格式以及输出到文件等
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s',
                    filename='multicast_receiver.log',
                    filemode='w')

# 创建命令行参数解析器
parser = argparse.ArgumentParser(description='组播消息接收程序')
# 组播组地址参数,默认值设为示例中的232.1.2.3,可通过命令行修改
parser.add_argument('-g', '--group', type=str, default='232.1.2.3', help='组播组地址')
# 组播端口号参数,默认值设为示例中的12345,可通过命令行修改
parser.add_argument('-p', '--port', type=int, default=12345, help='组播端口号')
#localaddress
parser.add_argument('-i', '--local', type=str, default="20.0.0.2", help='本地地址')
#output file
parser.add_argument('-o', '--output', type=str, default="output.file", help='输出文件')
args = parser.parse_args()

# 获取命令行传入的组播组地址和组播端口号
multicast_group = args.group
multicast_port = int(args.port)
local_address = args.local
filename = args.output

# 创建UDP套接字
sock = None
try:
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    logging.info("成功创建UDP套接字")
    if sock is None:
        raise Exception("创建套接字失败")

    # 设置套接字选项,允许重用地址
    try:
        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        logging.info("成功设置SO_REUSEADDR选项")
    except socket.error as e:
        logging.error("设置SO_REUSEADDR选项出错: "+e)
        raise

    # 将套接字绑定到本地所有可用地址(用空字符串表示)和指定的组播端口
    try:
        sock.bind(('', multicast_port))
        logging.info("成功将套接字绑定到端口: {}".format(multicast_port))
    except socket.error as e:
        logging.error("套接字绑定出错: {}".format(e))
        raise

    # 加入组播组
    try:
        group = socket.inet_aton(multicast_group)
        #mreq = struct.pack('4sL', group, socket.INADDR_ANY)
        local_addr = socket.inet_aton('20.0.0.2')
        local_addr = socket.inet_aton(local_address)
        mreq = struct.pack('4s4s', group, local_addr)
        sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
        logging.info("成功加入组播组 {}".format(multicast_group))
    except socket.error as e:
        logging.error("加入组播组出错: {}".format(e))
        raise

    # 循环接收组播消息
    tot_len = 0
    with open(filename, 'wb') as file:
      while True:
        try:
            sock.settimeout(5)  # 设置超时时间为5秒
            data, address = sock.recvfrom(1500)
            #logging.info("从 {} 接收到消息".format(address))
            if data.decode('utf-8') == "END":
                logging.info("完成接收")
                print("完成接收")
                break
            tot_len += len(data)
            file.write(data)
            print("从 {}接收到{}字节, total length: {}".format(address, len(data), tot_len))
        except socket.timeout:
            logging.info("接收超时,可能暂时没有组播消息到达")
            continue
        except socket.error as e:
            logging.error("接收组播消息出错: {e}".format(e))
            break

finally:
    # 关闭套接字释放资源
    if sock is not None:
        try:
            sock.close()
            logging.info("套接字已关闭")
        except socket.error as e:
            logging.error("关闭套接字时出错: {}".format(e))

你可能感兴趣的:(Python,网络编程,网络,python)