1. 程式人生 > >通過python下的socket實現組播資料的傳送和接收

通過python下的socket實現組播資料的傳送和接收

關於網路組播的解釋我不在此詳述了,想了解的直接百娘就可以了,本人也是新手,研究了幾天Python的組播程式設計後,目前終於成功的解決了自己找的各種麻煩,所以現在總結如下:

python實現socket組播有N種寫法,我現在只給出自己認為比較妥當的寫法。

資料傳送 sender:

import time
import struct
from socket import *

SENDERIP = '192.168.0.116'#本地ip
SENDERPORT = 1501#本地介面
MYPORT = 1234#傳送資料到該埠
MYGROUP = '224.1.1.1'#組播組
MYTTL = 255 # 傳送資料的TTL值

def sender():
    s = socket(AF_INET, SOCK_DGRAM,IPPROTO_UDP)
    s.bind((SENDERIP,SENDERPORT))
    # Set Time-to-live (optional)
    ttl_bin = struct.pack('@i', MYTTL)
    s.setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, ttl_bin)
    status = s.setsockopt(IPPROTO_IP,
        IP_ADD_MEMBERSHIP,
        inet_aton(MYGROUP) + inet_aton(SENDERIP))#加入到組播組
    while True:
        data = 'cisco'
        s.sendto(data + '\0', (MYGROUP, MYPORT))
        print "send data ok !"
        time.sleep(10)

if __name__ == "__main__":
    sender()

接收資料 receiver:

import time
import socket

SENDERIP = '192.168.0.116'
MYPORT = 1234
MYGROUP = '224.1.1.1'

def receiver():
    #create a UDP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
    #allow multiple sockets to use the same PORT number
    sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    #Bind to the port that we know will receive multicast data
    sock.bind((SENDERIP,MYPORT))
    #tell the kernel that we are a multicast socket
    #sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 255)
    #Tell the kernel that we want to add ourselves to a multicast group
    #The address for the multicast group is the third param
    status = sock.setsockopt(socket.IPPROTO_IP,
        socket.IP_ADD_MEMBERSHIP,
        socket.inet_aton(MYGROUP) + socket.inet_aton(SENDERIP));

    sock.setblocking(0)
    #ts = time.time()
    while 1:
        try:
            data, addr = sock.recvfrom(1024)
        except socket.error, e:
            pass
        else:
            print "Receive data!"

            print "TIME:" , time.time()
            print "FROM: ", addr
            print "DATA: ", data
if __name__ == "__main__":

    receiver()

不出意外的話,你按照以上兩個指令碼測試,在windows下是沒有問題。

可以實現的模式有:

windows  發資料 ,windows 接資料

Linux(如:CentOS) 發資料 ,windows 接資料

但是,linux接收資料,就不靈了。反正我試驗好久,也沒能成功。

ps:我親自試驗過,linux下用tcpdump抓包,是可以抓到的。

解決方法:

將receiver指令碼的sock.bind((SENDERIP,MYPORT))(也就是繫結IP)更改為空或者“0.0.0.0”,然後你再試一下,基本上就全都通了。

網上的解釋是,如果繫結為“0.0.0.0”,則表明是所有網絡卡的資料都可以接收到,但是我有點兒糊塗的地方是,我就一個網絡卡,而且只有個IP,難道我接受的資料不是通過這個IP接收到的?怪哉!

如果有大牛知道原因,請告知,謝謝!