说明:

控制器:pox betta版 ubuntu
组播程序:multicastv_8_9sw.py
需要修改的地方:
1:1906 2046行,交换机设定值是9,即要有九个交换机,多少个交换机这个值设定为多少。在def run2():函数里面和虚拟主机相连的交换机不能超过9个,且端口都接到4号端口。
2:1960行,监控流量的交换机的dpid,监控哪个写哪个
3:2010,2030等行自适应的机器10.0.0.60对应的mac地址要根据不同的机器改
4:1926 ,1968,2039行,sleep时间可以改变,即多少秒计算一次流量

Media server : ubuntu
发送程序:server.c h264.h multith8.py send_videolist_mediatomanage.py
需要修改的地方:
h264.h:
1: 29行 修改目的ip为10.0.0.50,目的端口都是49270
Server.c:
1:748行,修改发送视频源,da38.264视频为960x540,发送效果最好,空间可伸缩
2:1214, 1375行,修改sleep时间,不同视频时间不一样,da38.264都是4000,dayi.264为7000和8000
multith8.py:
1:166 ,404行,将mac值改为本机即为媒体服务器的mac
2:118,128,135行,将mac改为10.0.0.50对应机器的mac
send_videolist_mediatomanage.py:
1:29行,修改目录路径

客户端:ubuntu
接收程序:qclient
需要注意的地方:
1:安装g++,进入live文件夹,执行./genMakefiles linux,之后将文件夹拷到/usr/local/lib/中。
2:安装mplayer,./configure –enable-svc , make , sudo make install

客户端:windows
接收程序:qclient
需要注意的地方:
1:安装qt5,一直下一步, qt-opensource-windows-x86-msvc2010_opengl-5.3.1.exe 之后根据环境变量.txt修改环境变量:
2:将msvcp100d.dll,msvcr100d.dll复制到system32和syswow中
3:将MinGW拷到c盘,重新编译一遍或者在环境变量里面修改路径为lab3的都可以

Ostinato:ubuntu
需要注意的地方:
1:ip和mac地址千万不能写错,不然开启ostinato的时候交换机会挂掉
2:工作模式就是顺着视频流的方向
3:对于双网卡的机器,每个网卡都要对应一个固定的ip,不然重启交换机后两个网卡容易都是一个ip,这样启动控制器程序后会有问题

主要工作流程:

1,客户端向设备管理器请求视频:

def sendplay():
    global serverIp ,pulse ,GID,FID
    print "beginnnnnnnnnnnnnnnnn"
    if pulse == 1:
        print "pulse is iiiiiiiiiiiiiiiiiiiiiiiiiii"
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    
        port=50972      
        s.connect((serverIp,port))
        client = 1
        s.send(str(GID)+'#'+str(FID)+'#'+getHwAddr('eth0')+'#'+(s.getsockname()[0])+'#'+str(client))
        s.recv(1024)
        s.close()  
        time.sleep(1)
        thread.start_new_thread(mrun, (getHwAddr('eth0'),))
        time.sleep(1000)

发送的内容包括请求的视频组GID,层数FID,自身mac地址和套接字自身地址(ipaddr,port)。

2,设备管理器接受并处理消息:

(1)设备管理器接受info消息
str(GID)+’#’+str(FID)+’#’+getHwAddr(‘eth0’)+’#’+(s.getsockname()[0])

class clientToserver(threading.Thread):   #客户端到服务器  服务器侦听端口消息,等待客户端发信息,接受info消息str(GID)+'#'+str(FID)+'#'+getHwAddr('eth0')+'#'+(s.getsockname()[0])       
    def __init__(self):
        threading.Thread.__init__(self)
        self.thread_stop=False

    def run(self):
        while True:
            global info,con
            if con.acquire():  #获得锁
                print 'thread clienttoserver'
                print info
                self.socket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)    
                port=50972
                self.socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) 
                self.socket.bind((self.socket.getsockname()[0],port))  
                self.socket.listen(100)  
                if info is None:
                    connection,address=self.socket.accept() 
                    info=connection.recv(1024) 
                    self.socket.close()
                    print info

                con.release() #释放锁
                time.sleep(0.1)

    def stop(self):
            self.thread_stop=True

(2)处理info消息并发送给控制器:

处理思想如下:

dic[GID][FID]=[(mac1,ip1),(mac2,ip2)] 
dicp[GID][FID]=port    #GID表示视频组,FID表示请求视频层数
host [mac]=GID 
mactoip [mac]=ip

  info=str[GID]#str[FID]#mac#ip
  inf=info.split('#') #通过指定分隔符对字符串进行切片
  gid = int(inf[0])                      
  fid = int(inf[1])                      
  mac=inf[2]                     
  ip=inf[3]                    

一,该mac请求过视频(mac in host.keys()):
     【1】和原来请求视频不同(gid is not G):删除之前客户端的所在的视频组和层数信息,从新分配
               (1)如果客户端所请求的视频在之前的dic里(G in dic.keys()):
                  <1>层数相同(i in dic[G].keys()):  将mac ip添加到dic字典里:  dic[G][i].append((mac,ip))  
                  <2>层数之前没有:                             添加mac ip到新的dic :    dic[G][i]=[(mac,ip)] 
               (2)如果客户端所请求的视频不在之前的视频组dic里:加入 dic[G][i]=[(mac,ip)]
      【2】 请求的还是原来的视频(gid is G):
               <1> n > fid,新请求的视频层数没有原来的高,删除指定流        
               <2>n < fid,  新请求的视频层数比原来的高,加入指定流
二,该客户端的mac地址不在host{}里,即该客户端第一次请求视频:
     【1】如果客户端所请求的视频在之前的视频组里(G in dic.keys()):
                <1>层数相同(i in dic[G].keys()):  将mac ip添加到dic字典里:  dic[G][i].append((mac,ip))  
                 <2>层数之前没有:                             添加mac ip到新的dic :    dic[G][i]=[(mac,ip)] 
     【2】如果客户端所请求的视频不在之前的视频组里: 加入 dic[G][i]=[(mac,ip)]

同时将新信息发送给控制器:

self.s1=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port=8001
self.s1.connect(('10.0.0.200',port))
self.s1.send('i'+'#'+str(G)+str(i)+'#'+mac+'#'+ip+'#'+a+'#'+(self.s1.getsockname())[0]+'#'+str(dicp[G][i]))
self.s1.close()

info信息如下:

‘i’+’#’+str(G)+str(i)+’#’+mac+’#’+ip+’#’+a+’#’+(self.s1.getsockname())[0]+’#’+str(dicp[G][i])

其中 a为媒体服务器的mac 。


3,控制器接受并处理消息:

(1)def run() 接受处理消息:

接收到的info信息如下:

‘i’+’#’+str(G)+str(i)+’#’+mac+’#’+ip+’#’+a+’#’+(self.s1.getsockname())[0]+’#’+str(dicp[G][i])处理得到: 
 groupid = str(G)+str(i) 
 host = (mac,ip) 
 source = (a,self.s1.getsockname())[0]) 
 port = string.atoi(str(dicp[G][i])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  port = 8001
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
s.bind(('10.0.0.200',port))
s.listen(100)

connection, address = s.accept()
info = connection.recv(1024)

information = info.split('#')
    if information[0] == 'b':
      groupid = information[1]
      host = (information[2], information[3])
      source = (information[4], information[5])
      port = string.atoi(information[6])
      globle_sourcegroup[groupid] = (source[0], source[1], port)
      core.l2_multi.raiseEvent(MulticastInstall,groupid,source,host,port)
    if information[0] == 'i':
      groupid = information[1]
      host = (information[2], information[3])
      source = (information[4], information[5])
      port = string.atoi(information[6])
      core.l2_multi.raiseEvent(MulticastInsert,groupid,source,host,port,)
    if information[0] == 'd':
      groupid = information[1]
      host = (information[2], information[3])
      source = (information[4], information[5])
      port = string.atoi(information[6])
      core.l2_multi.raiseEvent(MulticastDelete,groupid,source,host,port,)
    connection.close()


(2)事件管理系统过程:

1,首先建立事件类:
PathInstalled,Switch,MulticastInstall,MulticastInsert,MulticastDelete。定义上述事件:

class PathInstalled (Event):
  """
  Fired when a path is installed
  """
  def __init__ (self, path):
    Event.__init__(self)
    self.path = path

class MulticastInstall(Event):
  def __init__(self,groupid,source,host,port):
    Event.__init__(self)
    self.groupid = groupid
    self.source = source
    self.host = host
    self.port = port

class MulticastInsert(Event):
  def __init__(self,groupid,source,host,port):
    Event.__init__(self)
    self.groupid = groupid
    self.source = source
    self.host = host
    self.port = port

class MulticastDelete(Event):
  def __init__(self,groupid,source,host,port):
    Event.__init__(self)
    self.groupid = groupid
    self.source = source
    self.host = host
    self.port = port

2,将定义好的事件注册到pox.core里,让pox知道这是个事件。创建raise事件的类,继承自EventMixin:

class l2_multi (EventMixin):

  _eventMixin_events = set([
    PathInstalled,
    MulticastInstall,
    MulticastInsert,
    MulticastDelete,
  ])

在最后的 def launch ()中的 core.registerNew(l2_multi) 注册组件。

3,创建处理事件的函数:

自动设置Listeners,处理函数有:
(1)def _handle_MulticastInstall(self,event):
(2)def _handle_MulticastInsert(self,event):
(3)def _handle_MulticastDelete(self,event):

class handlemulticast(object):
  def __init__(self):

    core.l2_multi.addListeners(self)

  def _handle_MulticastInstall(self,event):
    print 'handle multicastinstall'
    if event.groupid in globle_idgroup.keys():
      return
    else:
      src = (EthAddr(event.source[0]),IPAddr(event.source[1]))
      hst = {}
      hst[EthAddr(event.host[0])] = IPAddr(event.host[1])
      src_port = event.port
      print hst
      globle_idgroup[event.groupid] = multicast(src,hst,src_port)
      globle_idgroup[event.groupid].multicast_install()

  def _handle_MulticastInsert(self,event):
    print 'handle multicastinsert'
    if event.groupid not in globle_idgroup.keys():
      return
    else:
      hostmac = EthAddr(event.host[0])
      hostip = IPAddr(event.host[1])
      globle_idgroup[event.groupid].multicast_insert(hostmac,hostip)

  def _handle_MulticastDelete(self,event):
    print 'handle multicastdelete'
    if event.groupid not in globle_idgroup.keys():
      return 
    else:
      hostmac = EthAddr(event.host[0])
      globle_idgroup[event.groupid].multicast_delete(hostmac)
      if globle_idgroup[event.groupid].router_table == {}:
        del globle_idgroup[event.groupid]
        del globle_sourcegroup[event.groupid]

4,raise事件,触发事件:

即def run()中的以下语句:

core.l2_multi.raiseEvent(MulticastInstall,groupid,source,host,port)
 ...
core.l2_multi.raiseEvent(MulticastInsert,groupid,source,host,port,)
 ... 
core.l2_multi.raiseEvent(MulticastDelate,groupid,source,host,port,)

当达到某个条件后,开始触发MulticastInstall事件,并将参数传入,之后调用处理函数。

5,最后注册组件:

def launch ():
  core.registerNew(l2_multi)

core.register()指定一个对象; core.registerNew( )指定一个类.


(3)事件处理函数:

上述第三步 class handlemulticast(object) 中的处理函数主体:

def _handle_MulticastInstall(self,event):
    src = (EthAddr(event.source[0]),IPAddr(event.source[1]))
    hst[EthAddr(event.host[0])] = IPAddr(event.host[1])
    src_port = event.port
    globle_idgroup[event.groupid] = multicast(src,hst,src_port)
    globle_idgroup[event.groupid].multicast_install()

def _handle_MulticastInsert(self,event):
    hostmac = EthAddr(event.host[0])
    hostip = IPAddr(event.host[1])
    globle_idgroup[event.groupid].multicast_insert(hostmac,hostip)

def _handle_MulticastDelete(self,event):
    hostmac = EthAddr(event.host[0])
    globle_idgroup[event.groupid].multicast_delete(hostmac)

分别调用class multicast(object)中的
multicast_install(),multicast_insert(hostmac,hostip),multicast_delete(hostmac)函数下发流表。
其中初始化过程如下:

def __init__(self, src = None, hst = {}, src_port = 0): 
    self.source = src     #(sourcemac,sourceip)
    self.multicast_host = hst   #{hostmac:hostip}
    self.source_port = src_port
    self.inswitch = mac_map[src[0]][0] #mac_map[mac]=(sw,port) 
    self.inport = mac_map[src[0]][1]
    self.router_table = {}#{switch object:[(inport,outport)]}

可见,只需通过sourcemac和hostmac就能得到相连sw和port,通过
path = _get_path(sw1, sw2, firstport, finalport) 方法建立路径,之后下发流表。