Exemple #1
0
class MediaServer(object):
    '# Author: Hao Zhang\
     # Created: 02/11/2011\
     # Class: MediaServer - a TCP server that uploads data to users'

    def __init__(self, cwd, IS_SERVER=1):
        self.__cwd = cwd  # current working directory
        self.__isserver = IS_SERVER  # I mean the True server, not helper
        self.__tcpSerSock = Mytcpsocket()  # initiate server socket
        self.__tcpTracSock = Mytcpsocket()  # initiate tracker socket
        self.__PATH = self.__cwd + os.sep + SERVER_PATH + os.sep  # set up video caching directory
        if not os.path.exists(self.__PATH):
            os.makedirs(self.__PATH)

        # movieList: vhash: vname; videoDict: vhash: vpath; videoStat: vhash: [NumofChunks, NumofLeftOverPieces]
        self.__movieList = {}
        self.__videoDict = {}
        self.__videoStat = {}
        # storeAlloc: vhash: vsize; storePrices: vhash: vprice
        self.__storeAlloc = {}
        self.__storePrices = {}
        # mediaReaders: vhash: [a list of open file readers for vhash]; mediaUpdaters: vhash: file writer
        self.__mediaReaders = {}
        self.__mediaUpdaters = {}

        if IS_SERVER:
            self.__MaxNumConn = MAX_SERV_CONNECTION
            self.__Addr = MEDIA_SERVER_ADDRESS
            # read all the movies and convert newly added movies
            f = open(self.__PATH + 'movielist.txt', 'r+')
            allLines = f.readlines()
            f.close()
            for eachmovie in allLines:
                moviename = eachmovie.split('\n')[0]
                self.__movieList[hashlib.md5(
                    moviename).hexdigest()] = moviename  #vhash: vname
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if (
                        not os.path.isdir(self.__PATH + dname)
                ) and dname != 'movielist.txt':  # if video not converted, convert
                    hashname = hashlib.md5(dname.split('.')[0]).hexdigest()
                    if (hashname in self.__movieList
                            and not hashname in dirList):
                        videopath = self.__PATH + hashname
                        os.makedirs(videopath)
                        self.__convertVideo(videopath + os.sep, self.__PATH +
                                            dname)  # convert the video
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    if dname in self.__movieList:
                        self.__videoDict[dname] = videopath  # vhash: vpath
                        f = open(videopath + 'length', 'rb')
                        dt = f.readlines()
                        self.__videoStat[dname] = dt[0].split(',')
                        # vhash: [NumofChunks, NumofLeftoverPieces]
                        self.__mediaReaders[dname] = []
                    else:
                        print videopath  # not in list, to be deleted
                        shutil.rmtree(videopath)
        else:
            self.__MaxNumConn = MAX_PEER_CONNECTION
            # need to implement NAT traversal
            ##########start here############
            self.__Addr = (([
                ip for ip in gethostbyname_ex(gethostname())[2]
                if not ip.startswith("127.")
            ][0]), choice(range(50000, 60000)))
            ##########end   here############
            dirList = os.listdir(self.__PATH)
            for dname in dirList:
                if os.path.isdir(self.__PATH + dname):
                    videopath = self.__PATH + dname + os.sep
                    self.__videoDict[dname] = videopath
                    self.__mediaReaders[dname] = []
                    self.__mediaUpdaters[dname] = MediaFileWrapper(
                        videopath, False)  # write access
                    self.__storeAlloc[dname] = 0
                    self.__storePrices[dname] = 0

        self.__ClientNeighborhood = []
        self.__NumofConnections = 0
        self.__ClientConnectionIPs = []
        self.__ClientConnectionSocks = []
        self.__choketimer = 30

        self.__uploadBW = 0  # KB/sec
        self.__uploadedBytes = 0  # uploaded bytes in a second

        self.__UploadThreads = [
        ]  # upload threads. used to control UploadBWControl

        self.__neighborLock = thread.allocate_lock()
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__rateAllocLock = thread.allocate_lock()
        self.__mediaReaderLock = thread.allocate_lock()
        self.__uploadStatLock = thread.allocate_lock()
        self.__UploadThreadsLock = thread.allocate_lock()
        self.__BWControlBoot = threading.Event()
        self.__BWControlBoot.clear()
        # we don't need BW control all the time
        self.__uploadBWExceed = threading.Event()
        self.__uploadBWExceed.clear()
        self.__RateAllocBoot = threading.Event()
        self.__RateAllocBoot.clear()
        # we don't need rate allocation all the time

    def boot(self, uploadBW):
        self.__uploadBW = uploadBW  # force a virtual upload bandwidth; for testing reasons
        if VERBOSE:
            print 'Server %s goes online at %s' % (self.__Addr, ctime())
        ####### This is fake, just for testing purpose ################
        t = MyThread(self.__uploadBWControl, (1, ),
                     self.__uploadBWControl.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # rate allocation
        if not self.__isserver:
            t = MyThread(self.__rateallocation, (1, ),
                         self.__rateallocation.__name__)
            t.start()
            sleep(PROCESS_TIME)
        # register to the tracker
        t = MyThread(self.__commtotracker, (1, ),
                     self.__commtotracker.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # listen to passive connections
        t = MyThread(self.__WaitforConnection, (1, ),
                     self.__WaitforConnection.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # actively connect to client
        t = MyThread(self.__Connect2Client, self.__MaxNumConn,
                     self.__Connect2Client.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # choking
        t = MyThread(self.__choke, (1, ), self.__choke.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # user prompt
        t = MyThread(
            self.__userprompt, (1, ),
            self.__userprompt.__name__)  # open a new thread for new requests
        t.start()
        sleep(PROCESS_TIME)

    # This is an artificial upload BW control mechanism; only used for debugging purpose
    def __uploadBWControl(self, *targs):
        checkInterval = 0.1
        while True:
            self.__BWControlBoot.wait()
            # wait till there is at least one upload thread running
            self.__uploadStatLock.acquire()
            exceededBytesPerInterval = self.__uploadedBytes - checkInterval * self.__uploadBW
            self.__uploadStatLock.release()
            if exceededBytesPerInterval > 0:
                self.__uploadBWExceed.clear()
                ## fake wait to get more upload BW
                print 'exceeded'
                sleep(exceededBytesPerInterval / self.__uploadBW)
                print 'sleep over'
            # if there does not exist excessive bytes, the uploadBW will expire
            #print self.__uploadedBytes
            self.__uploadStatLock.acquire()
            self.__uploadedBytes = 0
            self.__uploadStatLock.release()
            self.__uploadBWExceed.set()
            sleep(checkInterval)  # check every second
            self.__UploadThreadsLock.acquire()
            ThreadstoRemove = []
            for eachThread in self.__UploadThreads:
                if not eachThread.isAlive():
                    ThreadstoRemove.append(eachThread)
            for eachRemoval in ThreadstoRemove:
                self.__UploadThreads.remove(eachRemoval)
            if len(self.__UploadThreads) == 0:
                self.__BWControlBoot.clear(
                )  # if no threads are running, stop uploadBW control thread
            self.__UploadThreadsLock.release()

        return

    def __choke(self, *targs):
        while True:
            self.__connectionLock.acquire()
            if self.__NumofConnections >= self.__MaxNumConn:
                ## re-code the choking algorithm by allocating the probabilities##
                ## START ##
                sockind = choice(range(self.__NumofConnections - 1))
                ## END ##
                self.__ClientConnectionSocks[sockind].close()
                del self.__ClientConnectionSocks[sockind]
                del self.__ClientConnectionIPs[sockind]
                self.__NumofConnections -= 1
            self.__connectionLock.release()
            if self.__NumofConnections < self.__MaxNumConn:
                self.__Connect2Client(1)  # connect to a new peer
            self.__timerLock.acquire()
            sleep(self.__choketimer)
            self.__timerLock.release()

    def __upload(self, *targs):
        args = targs[0]
        myClisock = args[0]
        cliAddr = args[1]
        ack = True
        avaPieces = None
        ClientFile = None
        while True:
            self.__BWControlBoot.set()
            self.__RateAllocBoot.set()
            data = myClisock.recvmsg(BUFSIZ)
            print data
            if data[0] == 'start':
                videohash = data[1]  # receive movie hash name
                if not videohash in self.__videoDict.keys(
                ):  # this will happen for helpers only. Server needs all videos
                    print self.__videoDict
                    os.makedirs(self.__PATH + videohash)
                    self.__videoDict[
                        videohash] = self.__PATH + videohash + os.sep
                    self.__mediaReaderLock.acquire()
                    self.__mediaReaders[videohash] = []
                    self.__mediaReaderLock.release()
                    if not self.__isserver:
                        self.__mediaUpdaters[videohash] = MediaFileWrapper(
                            self.__videoDict[videohash], False)  # write access
                        self.__rateAllocLock.acquire()
                        self.__storeAlloc[videohash] = 0
                        self.__storePrices[videohash] = 0
                        self.__rateAllocLock.release()
                ClientFile = MediaFileWrapper(self.__videoDict[videohash])
                self.__mediaReaders[videohash].append(
                    ClientFile)  # add the file reader
                myClisock.sendmsg('ACK')  # send ack
            elif data[0] == 'piece':
                if not self.__isserver:
                    if avaPieces != None:
                        if len(avaPieces) > 0:  # more video than needed
                            self.__rateAllocLock.acquire()
                            self.__storePrices[videohash] -= 1  # minus a token
                            print self.__storePrices
                            self.__rateAllocLock.release()
                        else:
                            pass
                avaPieces = ClientFile.getPieceIdbyChunk(data[1])
                ack = myClisock.sendmsg(avaPieces)
                print avaPieces
            elif data[0] == 'content':
                ChunkID, PieceID = data[1], data[2]
                datamsg = ClientFile.getPiecebyId(ChunkID, PieceID)
                if datamsg != None:  # found the piece
                    ack = myClisock.sendmsg('OK')
                    ## this is a fake constraint on upBW; only for testing purpose
                    self.__uploadBWExceed.wait()
                    ##############################################################
                    ack = myClisock.sendmsg(datamsg, True)
                    self.__uploadStatLock.acquire()
                    self.__uploadedBytes += BYTES_PER_PIECE
                    self.__uploadStatLock.release()
                    avaPieces = avaPieces.lstrip(
                        PieceID)  # remove the piece that is uploaded
                else:
                    ack = myClisock.sendmsg('XX')  # send out a none message
            elif data[0] == 'request':
                if not self.__isserver:
                    if avaPieces != None:
                        if len(avaPieces) == 0:  # could have more video
                            self.__rateAllocLock.acquire()
                            self.__storePrices[videohash] += 1  # plus a token
                            print self.__storePrices
                            self.__rateAllocLock.release()
            if not ack or data == 'closed':
                self.__pruneconnections(myClisock, cliAddr)
                if ClientFile != None:
                    ClientFile.closeAll()
                    self.__mediaReaderLock.acquire()
                    self.__mediaReaders[videohash].remove(ClientFile)
                    self.__mediaReaderLock.release()
                break

    def __download(self, vhashname, segID, pieceIDs):
        helper = MediaClient(self.__cwd)
        Success = helper.bootashelper(vhashname, segID, pieceIDs, self.__Addr)
        del helper
        return Success

    def __rateallocation(self, *targs):
        while True:
            self.__RateAllocBoot.wait()
            self.__rateAllocLock.acquire()
            if len(self.__storeAlloc) != 0:
                totalsiz = 0
                for vhash in self.__storeAlloc.keys():
                    self.__storeAlloc[vhash] = getFolderSize(
                        self.__videoDict[vhash])
                    totalsiz += self.__storeAlloc[
                        vhash]  # calculate the current total size
                pricevideos = zip(self.__storePrices.values(),
                                  self.__storePrices.keys())
                pricevideos.sort()
                sortedValues, sortedVideos = zip(*pricevideos)
                low = 0
                high = len(sortedValues) - 1
                self.__rateAllocLock.release()
                while low <= high:
                    if totalsiz < STORAGE_CAP:
                        if sortedValues[high] > 0:
                            totalsiz += self.__storageupdate(
                                sortedVideos[low],
                                totalsiz)  # ++ storage of high
                            high -= 1
                            continue
                        else:
                            break
                            # no update because not needed
                    if (abs(
                            sortedValues[low]
                    ) < ST_ALLOC_TH  # no update because it does not satisfy threshold
                            or abs(sortedValues[high]) < ST_ALLOC_TH):
                        break
                    if self.__mediaUpdaters[
                            sortedVideos[low]].getNumofSeg() <= 0:
                        low += 1
                        continue
                    if self.__mediaUpdaters[
                            sortedVideos[high]].getNumofSeg() >= SEG_PER_CHUNK:
                        high -= 1
                        continue
                    if sortedValues[low] < 0:
                        totalsiz += self.__storageupdate(
                            sortedVideos[low], totalsiz,
                            False)  # -- storage of low
                    if sortedValues[high] > 0:
                        totalsiz += self.__storageupdate(
                            sortedVideos[low], totalsiz)
                        # ++ storage of high
                self.__rateAllocLock.acquire()
                for vhash in self.__storePrices.keys():
                    self.__storePrices[vhash] = 0  # clear
                #self.__rateAllocLock.release();
            self.__rateAllocLock.release()
            sleep(INTERVAL_RATEALLOC)
            # don't need rate allocation when no download request is present
            self.__UploadThreadsLock.acquire()
            ThreadstoRemove = []
            for eachThread in self.__UploadThreads:
                if not eachThread.isAlive():
                    ThreadstoRemove.append(eachThread)
            for eachRemoval in ThreadstoRemove:
                self.__UploadThreads.remove(eachRemoval)
            if len(self.__UploadThreads) == 0:
                self.__RateAllocBoot.clear(
                )  # if no threads are running, stop rate allocation thread
            self.__UploadThreadsLock.release()

    # perform the storage add or removal given a video name
    def __storageupdate(self, vhashname, totalsiz, added=True):
        mul = 1
        if added:
            pieceIDs = self.__mediaUpdaters[vhashname].getNewPieceIDs()
            segID = self.__mediaUpdaters[vhashname].getNumofSeg() + 1
            rsize = self.__videoStat[vhashname][
                0] * BYTES_PER_CHUNK / SEG_PER_CHUNK
            if rsize + totalsiz < STORAGE_CAP:  # write if not exceed storage limit
                if not self.__download(vhashname, segID,
                                       pieceIDs):  # download data
                    rsize = 0
            else:
                rsize = 0
        else:
            mul = -1
        # the update process is self-locked because the MediaFileWrapper itself is a synchronized process
        UpdateSuccess = True
        self.__mediaReaderLock.acquire()
        for eachClientFile in self.__mediaReaders[vhashname]:
            UpdateSuccess = UpdateSuccess and eachClientFile.UpdateAccess(
                added)  # update file object for each peer
        self.__mediaReaderLock.release()
        self.__mediaUpdaters[vhashname].UpdateAccess(
            added)  # update file access
        if not added and UpdateSuccess:  # wait for close() before removal
            rsize = self.__mediaUpdaters[vhashname].removeSegment()
        return rsize * mul

    def __commtotracker(self, *targs):
        ack = False
        while not ack:
            ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
            if ack:
                countdown = 0
                while True:
                    if countdown == 0:
                        ack = self.__tcpTracSock.sendmsg('serv+' +
                                                         repr(self.__Addr[1]))
                        newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                        avaiMovieList = self.__tcpTracSock.recvmsg(BUFSIZ)
                        if (
                                not ack
                        ) or newneighborhood == 'closed' or avaiMovieList == 'closed':
                            ack = False
                            break
                        ACK = 'ACK'
                        if self.__isserver:
                            movienames = ""
                            for fhash, fname in self.__movieList.iteritems():
                                movienames = (movienames + '+' + fname + '#' +
                                              self.__videoStat[fhash][0] +
                                              '#' + self.__videoStat[fhash][1])
                            ack = self.__tcpTracSock.sendmsg('list' +
                                                             movienames)
                            ACK = self.__tcpTracSock.recvmsg(BUFSIZ)
                            if (not ack) or ACK == 'closed':
                                ack = False
                                break
                        else:
                            del self.__videoStat
                            self.__videoStat = {}
                            for eachmovie in avaiMovieList.keys():
                                self.__videoStat[hashlib.md5(
                                    eachmovie).hexdigest(
                                    )] = avaiMovieList[eachmovie]
                        self.__neighborLock.acquire()
                        self.__ClientNeighborhood = union(
                            self.__ClientNeighborhood, newneighborhood)
                        ## might have to set a maximum limit of neighborhood ##
                        self.__neighborLock.release()
                        countdown = OBTAIN_NEIGHBOR_PERIOD / INTERVAL_TRACKER_COMMUNICATION
                    else:
                        ack = self.__tcpTracSock.sendmsg('alive')
                        if not ack:
                            break
                        sleep(INTERVAL_TRACKER_COMMUNICATION)
                        countdown -= 1
            sleep(TRY_INTERVAL)
            del self.__tcpTracSock
            self.__tcpTracSock = Mytcpsocket()

    def __Connect2Client(self, number):
        self.__connectionLock.acquire()
        self.__neighborLock.acquire()
        Neighborhood = lminus(self.__ClientNeighborhood,
                              self.__ClientConnectionIPs)
        potentialconnect = sample(Neighborhood, min(len(Neighborhood), number))
        for eachClient in potentialconnect:
            if self.__NumofConnections < self.__MaxNumConn:
                if eachClient not in self.__ClientConnectionIPs:
                    cliSock = Mytcpsocket()
                    ack1 = cliSock.Connect2Server(eachClient)
                    ack2 = cliSock.sendmsg(self.__Addr[1])
                    ack3 = cliSock.recvmsg(BUFSIZ)  # receive ACK
                    if ack1 and ack2 and ack3 != 'closed':
                        self.__NumofConnections += 1
                        self.__ClientConnectionSocks.append(cliSock)
                        self.__ClientConnectionIPs.append(eachClient)
                        t = MyThread(self.__upload, (cliSock, eachClient),
                                     self.__upload.__name__)
                        self.__UploadThreadsLock.acquire()
                        self.__UploadThreads.append(t)
                        self.__UploadThreadsLock.release()
                        self.__BWControlBoot.set()
                        # start BW control
                        self.__RateAllocBoot.set()
                        # start rate allocation
                        t.start()
                        sleep(PROCESS_TIME)
                    else:
                        self.__ClientNeighborhood.remove(eachClient)
            else:
                break
        self.__connectionLock.release()
        self.__neighborLock.release()

    def __WaitforConnection(self, *targs):
        self.__tcpSerSock.InitServSock(self.__Addr, self.__MaxNumConn)
        if VERBOSE:
            print "Waiting for connection..."
        while True:
            (tcpClientSock, CLIENT_ADDR) = self.__tcpSerSock.WaitforConn()
            self.__connectionLock.acquire()
            clitcpsock = Mytcpsocket(tcpClientSock)
            if self.__NumofConnections < self.__MaxNumConn:
                servport = clitcpsock.recvmsg(BUFSIZ)
                ack = clitcpsock.sendmsg('ACK')
                CLIENT_SERV_ADDR = (CLIENT_ADDR[0], servport)
                if ((CLIENT_SERV_ADDR in self.__ClientConnectionIPs)
                        or (not ack) or servport == 'closed'):
                    clitcpsock.close()
                else:
                    self.__ClientConnectionSocks.append(clitcpsock)
                    self.__ClientConnectionIPs.append(CLIENT_SERV_ADDR)
                    self.__NumofConnections += 1
                    if VERBOSE:
                        print "...connected from:", CLIENT_ADDR
                    t = MyThread(self.__upload, (clitcpsock, CLIENT_SERV_ADDR),
                                 self.__upload.__name__)
                    self.__UploadThreadsLock.acquire()
                    self.__UploadThreads.append(t)
                    self.__UploadThreadsLock.release()
                    self.__BWControlBoot.set()
                    # start BW control
                    self.__RateAllocBoot.set()
                    # start rate allocation
                    t.start()
                    sleep(PROCESS_TIME)
            else:
                clitcpsock.close(
                )  # close if the number of connections exceeds max
            self.__connectionLock.release()

    # no random coding of the pieces yet. need to modify the function if needed to do so.
    def __convertVideo(self, path, fname):
        FILES = []
        METAS = []
        vidfile = open(fname, 'rb')
        for segNum in range(SEG_PER_CHUNK):
            file = open(path + 'seg' + repr(segNum + 1) + FILE_SUFFIX, 'wb+')
            meta = open(path + 'seg' + repr(segNum + 1) + META_SUFFIX, 'wb+')
            FILES.append(file)
            METAS.append(meta)
            Ind = 0
        data = vidfile.read(BYTES_PER_SEG)
        numofchunks = 0
        numofleftpieces = 0
        while data != "":
            wlen = len(data) * 1.0 / BYTES_PER_PIECE
            if wlen < PIECE_PER_SEG:
                wlen = ceil(wlen)
                data = pack(str(int(wlen * BYTES_PER_PIECE)) + 's', data)
            numofleftpieces += wlen
            FILES[Ind].write(data)
            METAS[Ind].write(
                PIECE_IDS[Ind * PIECE_PER_SEG:Ind * PIECE_PER_SEG + int(wlen)])
            Ind += 1
            Ind = Ind % SEG_PER_CHUNK
            data = vidfile.read(BYTES_PER_SEG)
        vidfile.close()
        numofchunks = int(numofleftpieces / PIECE_PER_CHUNK)
        numofleftpieces = int(numofleftpieces % PIECE_PER_CHUNK)
        if numofleftpieces == 0:
            numofleftpieces = PIECE_PER_CHUNK
        f = open(path + 'length', 'wb+')
        f.write(str(numofchunks) + ',' + str(numofleftpieces))
        f.close()
        for segNum in range(SEG_PER_CHUNK):
            FILES[segNum].close()
            METAS[segNum].close()

    def __userprompt(self, *args):
        while True:
            userinput = raw_input(
                'Input your choice:\n[1] Print Neighbors\n[2] Print Connections\nYour choice>> '
            )
            if userinput == '1':
                self.__printAllNeighbors()
            if userinput == '2':
                self.__printAllConnections()
            else:
                pass

    def __pruneconnections(self, tcpsock, Addr):
        self.__connectionLock.acquire()
        self.__ClientConnectionSocks.remove(tcpsock)
        self.__ClientConnectionIPs.remove(Addr)
        self.__NumofConnections -= 1
        self.__connectionLock.release()

    def __printAllNeighbors(self):
        for eachNeighbor in self.__ClientNeighborhood:
            print eachNeighbor

    def __printAllConnections(self):
        for eachConnectionIP in self.__ClientConnectionIPs:
            print eachConnectionIP
        for eachConnectionSock in self.__ClientConnectionSocks:
            print eachConnectionSock
Exemple #2
0
class Tracker(object):
    def __init__(self, Tracker_Addr=TRACKER_ADDRESS):
        self.__socket = Mytcpsocket()  # a new socket
        self.__Addr = Tracker_Addr  # IP address + port
        self.__MaxNumConn = MAX_TRAC_CONNECTION
        self.__userDict = {}  # connecting addresses of active (estimate) users
        self.__servDict = {
        }  # connecting addresses of active (estimate) helpers
        #self.__servDict[MEDIA_SERVER_ADDRESS] = 1      # the central server
        self.__inputLock = thread.allocate_lock(
        )  # lock for the input variables
        self.__EXIT = 0  # exit the system or not
        self.__movieList = {}  # list of movie names

    def __userprompt(self, *args):
        while True:
            userinput = raw_input(
                'Input your choice:\n[0] Print All Movies\n[1] Print Registered Peers\n[2] Disconnect\nYour choice>> '
            )
            if userinput == '0':
                self.__printAllMovies()
            elif userinput == '1':
                self.__printAllregistered()
            elif userinput == '2':
                self.__inputLock.acquire()
                self.__EXIT = 1
                self.__inputLock.release()
                break
            else:
                pass

    def boot(self):
        t = MyThread(
            self.__userprompt, (1, ),
            self.__userprompt.__name__)  # open a new thread for new requests
        t.start()
        sleep(PROCESS_TIME)

        self.__socket.InitServSock(self.__Addr, self.__MaxNumConn)
        while True:
            (tcpCliSock, CIENT_ADDR) = self.__socket.WaitforConn()
            t = MyThread(self.__registerpeer, (tcpCliSock, CIENT_ADDR),
                         self.__registerpeer.__name__
                         )  # open a new thread for new requests
            #self.__threads.append(t)
            t.start()
            sleep(PROCESS_TIME)  # allow process time for the thread
            self.__inputLock.acquire()
            if self.__EXIT == 1:
                self.__socket.close()
                break
            self.__inputLock.release()

    def __registerpeer(
            self, *targs
    ):  # register the peer and obtain a list of potential neighbors
        args = targs[0]
        CliSocket = args[0]
        CliAddr = args[1]
        myClisock = Mytcpsocket(CliSocket)
        IS_SERV = -1
        while True:
            data = myClisock.recvmsg(BUFSIZ)
            if 'serv' in str.lower(data):
                IS_SERV = 1
                CliAddr = (CliAddr[0], int(data.split('+')[1]))
                self.__servDict[CliAddr] = 1
                pc = self.__potentialconn(
                    CliAddr, self.__userDict
                )  # return a list of user addresses \ itself
                myClisock.sendmsg(pc)
                myClisock.sendmsg(self.__movieList)  # send movie list to watch
            elif 'user' in str.lower(data):
                IS_SERV = 0
                CliAddr = (CliAddr[0], int(data.split('+')[1]))
                self.__userDict[CliAddr] = 1
                pc = self.__potentialconn(
                    CliAddr, self.__servDict
                )  # return a list of serv addresses \ itself
                myClisock.sendmsg(pc)
                myClisock.sendmsg(self.__movieList)  # send movie list to watch
            elif 'list' in str.lower(data):
                data = data.split('+')
                for i in range(1, len(data)):
                    videostat = data[i].split('#')
                    self.__movieList[videostat[0]] = [
                        int(videostat[1]),
                        int(videostat[2])
                    ]
                myClisock.sendmsg('ACK')
            elif str.lower(data) == 'alive':  # still alive
                print data, ' from ', CliAddr
                pass
            else:
                if IS_SERV == 1:
                    self.__servDict.pop(CliAddr)
                elif IS_SERV == 0:
                    self.__userDict.pop(CliAddr)
                myClisock.close()  # close the connection
                break

    def __potentialconn(self, CliAddr, PotentialConnections):
        'return a list of potential connections -- list of IP/ports in the other Dictionary set-minus itself'

        def notself(query):
            return (CliAddr != query)

        return filter(
            notself,
            sample(PotentialConnections,
                   min(len(PotentialConnections), NUM_RETURNED_PEERS)))

    def __printAllregistered(self):
        print 'Registered users:'
        for eachUsr in self.__userDict:
            print eachUsr
        print '\nRegistered servers:'
        for eachServ in self.__servDict:
            print eachServ

    def __printAllMovies(self):
        for i, eachmovie in enumerate(self.__movieList):
            print repr(i + 1) + '. ' + eachmovie
Exemple #3
0
class MediaClient(object):
    '# Author: Hao Zhang\
     # Created: 02/11/2011\
     # Class: MediaClient - a TCP client  that downloads data from the servers'

    # Initialization -- set up address and port; initilize parameters
    def __init__(self, cwd):
        self.__cwd = cwd  # current working directory
        self.__BootedasUser = True
        self.__tcpTracSock = Mytcpsocket()
        self.__tcpListenSock = Mytcpsocket()
        self.__MaxNumConn = MAX_PEER_CONNECTION
        self.__Addr = (([
            ip for ip in gethostbyname_ex(gethostname())[2]
            if not ip.startswith("127.")
        ][0]), choice(range(50000, 60000)))

        self.__tcpCliSockets = []
        self.__ServerNeighborhood = []
        self.__ServerConnectionIPs = []
        self.__ServerConnectionSocks = []
        self.__NumofConnections = 0
        self.__ExcludedServerAddr = []
        self.__choketimer = 30
        self.__StartWaiting = False

        self.__receivedFile = None  # streaming file object
        self.__avaiMovieList = {}  # available movie list from the tracker
        self.__movieHashNames = {}
        self.__currentvid = 'None'  # current video that is being watched
        self.__NumofChunks = 0
        self.__NumofLeftPieces = 0

        self.__neighborLock = thread.allocate_lock(
        )  # lock for the neighborhood update
        self.__connectionLock = thread.allocate_lock()
        self.__timerLock = thread.allocate_lock()
        self.__streamingStatLock = thread.allocate_lock()
        self.__bufferStatLock = thread.allocate_lock()
        self.__emptyAvailable = threading.Event()
        self.__emptyAvailable.clear()
        # one of the download chunks is waiting for other corresponding threads to finish that chunk
        self.__DownloadWait = threading.Event()
        self.__DownloadWait.clear()
        # wait till download is finished
        self.__BufferFullWait = threading.Event()
        self.__BufferFullWait.clear()
        # buffer too much, wait before download
        self.__BufferEmptyWait = threading.Event()
        self.__BufferEmptyWait.clear()
        # buffer not enough, download from server
        self.__streamingWait = threading.Event()
        self.__streamingWait.clear()
        # wait till buffer is ready to stream
        self.__downloadthreads = []
        self.__EXIT = False

    # Boot as a pure user with prompt
    def bootasuser(self):
        self.__streamingPath = self.__cwd + os.sep + CLIENT_PATH + os.sep
        if not os.path.exists(self.__streamingPath):
            os.makedirs(self.__streamingPath)
        self.__PiecestoDownload = PIECE_IDS  # as a user, download all the pieces
        self.__PiecesperChunk = PIECE_PER_CHUNK
        if VERBOSE:
            print 'User %s goes online at %s' % (self.__Addr, ctime())
        # register to the tracker
        t = MyThread(self.__commtotracker, (1, ),
                     self.__commtotracker.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # choking
        t = MyThread(self.__choke, (1, ), self.__choke.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # enable user prompt
        t = MyThread(
            self.__userprompt, (1, ),
            self.__userprompt.__name__)  # open a new thread for new requests
        t.start()
        sleep(PROCESS_TIME)

    # Boot as a downloader to get packets (as a helper)
    def bootashelper(self, videohash, segID, piecestodownload,
                     excludedServerAddr):
        self.__BootedasUser = False
        self.__ExcludedServerAddr = excludedServerAddr
        self.__PiecestoDownload = piecestodownload  # as a helper, specify pieces to download
        self.__PiecesperChunk = len(piecestodownload)
        self.__streamingPath = self.__cwd + os.sep + SERVER_PATH + os.sep + videohash + os.sep + 'seg' + str(
            segID) + FILE_SUFFIX
        self.__MetaPath = self.__cwd + os.sep + SERVER_PATH + os.sep + videohash + os.sep + 'seg' + str(
            segID) + META_SUFFIX
        self.__BufferFullWait.set()  # no need to buffer download for helper
        #### need a mechanism to control this: need to be either too greedy or too conservative
        self.__BufferEmptyWait.set()
        ######

        # register to the tracker
        t = MyThread(self.__commtotracker, (1, ),
                     self.__commtotracker.__name__)
        t.start()
        sleep(PROCESS_TIME * 2)
        # choking
        t = MyThread(self.__choke, (1, ), self.__choke.__name__)
        t.start()
        sleep(PROCESS_TIME)
        # enable download
        self.__movieInitialize(videohash)
        sleep(PROCESS_TIME)
        self.__DownloadWait.wait()
        # wait until download is finished
        self.__EXIT = True
        return True

    def __bufferControl(self, *targs):
        while True:
            if self.__EXIT:
                return
            self.__streamingStatLock.acquire()
            if self.__streamedNumofChunks >= self.__NumofChunks:
                print self.__NumofChunks, self.__streamedNumofChunks
                self.__streamingWait.set()
                # let the stream break
                self.__streamingStatLock.release()
                break
            if self.__streamingBufferLength < 1:  # less than a second of buffer to play
                self.__streamingWait.clear()  # stop streaming
                self.__BufferEmptyWait.set()
                self.__BufferFullWait.set()
                # start downloading NOW!
            else:
                self.__streamingWait.set()  # let it stream
                if self.__streamingBufferLength >= BUFFER_TOO_MUCH:  # buffer too much
                    self.__BufferFullWait.clear()
                    self.__BufferEmptyWait.clear()  # stop downloading
                elif self.__streamingBufferLength >= BUFFER_LENGTH:
                    self.__BufferEmptyWait.clear()
                elif self.__streamingBufferLength < BUFFER_LENGTH:  # buffer less than required length
                    self.__BufferFullWait.set()  # download from helpers
                    if self.__streamingBufferLength < BUFFER_EMERG_LEFT:  # if less than emergency
                        self.__BufferEmptyWait.set(
                        )  # download from the SERVER
                    else:
                        self.__BufferEmptyWait.clear()
            self.__streamingStatLock.release()
            sleep(BUFFER_CHECK_INTERVAL)

    def __streaming(self, *targs):
        speedup = 1
        while True:
            if self.__EXIT:
                return
            self.__streamingWait.wait()
            ### stream the video NOW for duration xxx ###
            ### Now it is Fake streaming ###
            sleep(1)
            self.__streamingStatLock.acquire()
            if self.__streamingBufferLength > 1:
                self.__streamingBufferLength -= speedup
                print 'subtracted, BufferLength = ', self.__streamingBufferLength
                self.__streamedNumofChunks += speedup * self.__streamingRate / BYTES_PER_CHUNK
            if self.__streamedNumofChunks >= self.__NumofChunks:
                print self.__NumofChunks, self.__streamedNumofChunks
                self.__streamingStatLock.release()
                break
            self.__streamingStatLock.release()
            ################################

    def __choke(self, *targs):
        while True:
            if self.__EXIT:
                return
            self.__connectionLock.acquire()
            if self.__NumofConnections >= self.__MaxNumConn:
                ## re-code the choking algorithm by allocating the probabilities##
                ## START ##
                sockind = choice(range(self.__NumofConnections - 1))
                ## END ##
                self.__ServerConnectionSocks[sockind].close()
                del self.__ServerConnectionSocks[sockind]
                del self.__ServerConnectionIPs[sockind]
                self.__NumofConnections -= 1
            self.__connectionLock.release()
            if self.__NumofConnections < self.__MaxNumConn and self.__currentvid != 'None':
                self.__Connect2Server(
                    (1, self.__currentvid))  # connect to a new peer
            self.__timerLock.acquire()
            sleep(self.__choketimer)
            self.__timerLock.release()

    def __download(self, *targs):
        args = targs[0]
        servSock = args[0]
        servAddr = args[1]
        videohash = args[2]
        self.__DownloadWait.clear()
        while True:
            if videohash == 'None':
                servSock.sendmsg('closed')
                self.__pruneconnections(servSock, servAddr)
                self.__DownloadWait.set()
                return
            ack = servSock.sendmsg(['start',
                                    videohash])  # send which video to watch
            ACK = servSock.recvmsg(BUFSIZ)  # receive acknowledgement
            if not ack or ACK == 'closed':
                self.__pruneconnections(servSock, servAddr)
                self.__DownloadWait.set()
                return
            currentChunkID = -1
            piecesperchunk = self.__PiecesperChunk
            while True:
                if self.__EXIT:
                    return
                if servAddr == MEDIA_SERVER_ADDRESS:  # wait until buffer is too little
                    self.__BufferEmptyWait.wait()
                else:  # wait until buffer is less than a certain threshold
                    self.__BufferFullWait.wait()
                self.__bufferStatLock.acquire()
                if videohash != self.__currentvid:
                    videohash = self.__currentvid
                    self.__bufferStatLock.release()
                    break
                if currentChunkID < self.__bufferheadChunkID:
                    currentChunkID = self.__bufferheadChunkID
                    self.__bufferStatLock.release()
                    ack = servSock.sendmsg(['piece', currentChunkID])
                    #print ack
                    avaiPieceIDsfromServ = servSock.recvmsg(BUFSIZ)
                    #print avaiPieceIDsfromServ
                    if not ack or avaiPieceIDsfromServ == 'closed':
                        self.__pruneconnections(servSock, servAddr)
                        self.__DownloadWait.set()
                        return
                    continue
                avaiPieceIDsfromServ = intersect(
                    avaiPieceIDsfromServ, self.__avaiPieceIDs
                )  # Now I am sure no other peers are giving me the same data
                RequestingSet = lminus(avaiPieceIDsfromServ,
                                       self.__PiecesNowRequested)
                #print RequestingSet, "from", servAddr
                if len(RequestingSet) == 0:
                    if len(
                            lminus(self.__avaiPieceIDs,
                                   self.__PiecesNowRequested)) > 0:
                        ack = servSock.sendmsg(['request'])
                        if not ack:
                            self.__pruneconnections(servSock, servAddr)
                            self.__bufferStatLock.release()
                            self.__DownloadWait.set()
                            return
                    self.__bufferStatLock.release()
                    self.__emptyAvailable.wait(
                        BUFFER_EMERG_LEFT)  # wait until this chunk is over
                    continue
                PiecesToRequest = choice(
                    RequestingSet)  # randomly choose an available piece
                self.__PiecesNowRequested.extend(
                    PiecesToRequest)  # put it into the requesting queue
                self.__bufferStatLock.release()
                ack = servSock.sendmsg(
                    ['content', currentChunkID,
                     PiecesToRequest])  # download the piece
                ACK = servSock.recvmsg(BUFSIZ)
                if ACK == 'OK':
                    data = servSock.recvmsg(
                        BYTES_PER_PIECE,
                        True)  # only receive if server still has it
                else:  # if ACK == 'XX'
                    avaiPieceIDsfromServ.remove(
                        PiecesToRequest)  # otherwise remove it and continue
                    self.__PiecesNowRequested = lminus(
                        self.__PiecesNowRequested, PiecesToRequest)
                    continue
                #print data[0:5]
                print "data from server", servAddr
                self.__bufferStatLock.acquire()
                if videohash != self.__currentvid:  # if no longer watching current video, leave
                    videohash = self.__currentvid
                    self.__bufferStatLock.release()
                    break
                if not ack or data == 'closed':  # check if the connection is still alive
                    self.__pruneconnections(servSock, servAddr)
                    self.__PiecesNowRequested = lminus(
                        self.__PiecesNowRequested, PiecesToRequest)
                    self.__bufferStatLock.release()
                    self.__DownloadWait.set()
                    return
                if currentChunkID < self.__bufferheadChunkID:  # if other processes have already advanced the chunk, then dump it
                    self.__bufferStatLock.release()
                    continue
                # finally I made sure the downloaded pieces is valid and needed
                self.__PiecesNowRequested = lminus(
                    self.__PiecesNowRequested,
                    PiecesToRequest)  # change status requested to available
                self.__avaiPieceIDs = lminus(self.__avaiPieceIDs,
                                             PiecesToRequest)
                self.__bufferPieceIDs.extend(PiecesToRequest)
                self.__bufferContent.append(data)
                if len(self.__bufferPieceIDs
                       ) >= piecesperchunk:  # finished downloading of a chunk
                    sortedIDs, self.__bufferContent = PacketsDecode(
                        self.__bufferContent, self.__bufferPieceIDs)
                    if self.__BootedasUser:
                        ##### feed the buffer to the streaming wrapper #####
                        ##### now just write the file #####
                        self.__receivedFile.write(self.__bufferContent)
                        ##### END #########################
                    else:
                        self.__MetaFile.write(sortedIDs)
                        self.__receivedFile.write(self.__bufferContent)
                    self.__streamingStatLock.acquire()
                    # change streaming buffer length in seconds
                    self.__streamingBufferLength += piecesperchunk * BYTES_PER_PIECE / self.__streamingRate
                    print 'added, BufferLength = ', self.__streamingBufferLength
                    self.__streamingStatLock.release()
                    self.__bufferPieceIDs = []
                    self.__bufferContent = []
                    self.__PiecesNowRequested = []
                    self.__avaiPieceIDs = self.__PiecestoDownload
                    piecesperchunk = self.__PiecesperChunk
                    self.__bufferheadChunkID += 1
                    if self.__bufferheadChunkID == self.__NumofChunks:
                        self.__avaiPieceIDs = intersect(
                            PIECE_IDS[0:self.__NumofLeftPieces],
                            self.__PiecestoDownload)  # last chunk left pieces
                        piecesperchunk = len(self.__avaiPieceIDs)
                    if self.__bufferheadChunkID > self.__NumofChunks or piecesperchunk == 0:
                        self.__currentvid = 'None'  # finish download
                        self.__NumofChunks = 0
                        self.__receivedFile.close()
                        if not self.__BootedasUser:
                            self.__MetaFile.close()
                        self.__DownloadWait.set()
                        # set the wait to finish
                    self.__emptyAvailable.set()
                    # release the available ID empty lock
                    self.__emptyAvailable.clear()
                    # set the lock again for next round
                self.__bufferStatLock.release()

    def __movieInitialize(self, videohash):
        ## dump all current                                # dump the current streaming if possible
        self.__bufferStatLock.acquire()
        if self.__currentvid == videohash:
            self.__bufferStatLock.release()
            return
        #### movie paramter initialization:
        self.__streamingRate = BYTES_PER_CHUNK / BUFFER_LENGTH
        self.__streamingBufferLength = 0  # in units of seconds
        self.__streamedNumofChunks = 0  # number of chunks that are streamed
        self.__bufferheadChunkID = 0  # the chunk ID in front of the buffer
        self.__bufferContent = []  # integer IDs
        self.__bufferPieceIDs = []  # string names
        self.__PiecesNowRequested = []  # pieces that are now requested
        self.__avaiPieceIDs = self.__PiecestoDownload  # initialize available pieces to watch
        self.__streamingWait.clear()
        self.__BufferFullWait.clear()
        self.__BufferEmptyWait.clear()
        if videohash != 'None':  # if a movie was requested
            self.__NumofChunks = self.__movieHashNames[videohash][0]
            self.__NumofLeftPieces = self.__movieHashNames[videohash][1]
            self.__currentvid = videohash
            if self.__receivedFile != None:  # close the opened file
                self.__receivedFile.close()
            if self.__BootedasUser:
                writeFilePath = self.__streamingPath + videohash + '.flv'
                #writeFilePath = self.__streamingPath + 'hancock-tsr2_h480p' + '.flv'
            else:
                writeFilePath = self.__streamingPath
                self.__MetaFile = open(self.__MetaPath, 'w+b')
            self.__receivedFile = open(writeFilePath,
                                       'w+b')  # open a writable file
            if self.__BootedasUser:
                t = MyThread(self.__bufferControl, (1, ),
                             self.__bufferControl.__name__)
                t.start()
                sleep(PROCESS_TIME)
                # start buffer control
                t = MyThread(self.__streaming, (1, ),
                             self.__streaming.__name__)
                # start streaming
                t.start()
                sleep(PROCESS_TIME)
            else:
                self.__BufferEmptyWait.set()
                self.__BufferFullWait.set()
            t = MyThread(self.__Connect2Server, (self.__MaxNumConn, videohash),
                         self.__Connect2Server.__name__)
            t.start()
            sleep(PROCESS_TIME)
            if self.__StartWaiting == False:  # listen to active server to user connections
                self.__StartWaiting = True
                t = MyThread(self.__WaitforConnection, (1, ),
                             self.__WaitforConnection.__name__)
                t.start()
                sleep(PROCESS_TIME)
        else:
            self.__NumofChunks = 0
            self.__NumofLeftPieces = 0
            self.__currentvid = 'None'  # not watching any videos
        self.__bufferStatLock.release()

    def __commtotracker(self, *targs):
        ack = False
        while not ack:
            if self.__EXIT:
                return
            ack = self.__tcpTracSock.Connect2Server(TRACKER_ADDRESS)
            #print TRACKER_ADDRESS
            if ack:
                countdown = 0
                while True:
                    if self.__EXIT:
                        return
                    if countdown == 0:
                        ack = self.__tcpTracSock.sendmsg('user+' +
                                                         repr(self.__Addr[1]))
                        newneighborhood = self.__tcpTracSock.recvmsg(BUFSIZ)
                        self.__avaiMovieList = self.__tcpTracSock.recvmsg(
                            BUFSIZ)
                        if (
                                not ack
                        ) or newneighborhood == 'closed' or self.__avaiMovieList == 'closed':
                            ack = False
                            break
                        del self.__movieHashNames
                        self.__movieHashNames = {}
                        for eachmovie in self.__avaiMovieList.keys():
                            self.__movieHashNames[hashlib.md5(
                                eachmovie).hexdigest(
                                )] = self.__avaiMovieList[eachmovie]
                        self.__neighborLock.acquire()
                        ## might have to set a maximum limit of neighborhood ##
                        self.__ServerNeighborhood = union(
                            self.__ServerNeighborhood, newneighborhood)
                        self.__ServerNeighborhood = lminus(
                            self.__ServerNeighborhood,
                            self.__ExcludedServerAddr)
                        self.__neighborLock.release()
                        countdown = OBTAIN_NEIGHBOR_PERIOD / INTERVAL_TRACKER_COMMUNICATION
                    else:
                        ack = self.__tcpTracSock.sendmsg('alive')
                        if not ack:
                            break
                        sleep(INTERVAL_TRACKER_COMMUNICATION)
                        countdown -= 1
                        # send alive msg interval
            sleep(TRY_INTERVAL)  # obtain neighborhood/movielist interval
            del self.__tcpTracSock
            self.__tcpTracSock = Mytcpsocket()

    def __WaitforConnection(self, *targs):
        self.__tcpListenSock.InitServSock(self.__Addr, self.__MaxNumConn)
        while True:
            if self.__EXIT:
                return
            (tcpServSock, SERVER_ADDR) = self.__tcpListenSock.WaitforConn()
            self.__connectionLock.acquire()
            servtcpsock = Mytcpsocket(tcpServSock)
            if self.__NumofConnections < self.__MaxNumConn:
                servport = servtcpsock.recvmsg(BUFSIZ)
                ack = servtcpsock.sendmsg('ACK')  # send ACK
                SERVER_SERV_ADDR = (SERVER_ADDR[0], servport)
                if ((SERVER_SERV_ADDR in self.__ServerConnectionIPs)
                        or (SERVER_SERV_ADDR == self.__ExcludedServerAddr)
                        or (not ack) or servport == 'closed'):
                    servtcpsock.close()
                else:
                    self.__ServerConnectionSocks.append(servtcpsock)
                    self.__ServerConnectionIPs.append(SERVER_SERV_ADDR)
                    self.__NumofConnections += 1
                    if VERBOSE:
                        print "...connected from:", SERVER_SERV_ADDR
                    t = MyThread(
                        self.__download,
                        (servtcpsock, SERVER_SERV_ADDR, self.__currentvid),
                        self.__download.__name__)
                    t.start()
                    sleep(PROCESS_TIME)
                    self.__downloadthreads.append(t)
            else:
                servtcpsock.close(
                )  # close if the number of connections exceeds max
            self.__connectionLock.release()

    def __Connect2Server(self, *targs):
        args = targs[0]
        number = args[0]
        videohash = args[1]
        self.__connectionLock.acquire()
        self.__neighborLock.acquire()
        Neighborhood = lminus(self.__ServerNeighborhood,
                              self.__ServerConnectionIPs)
        potentialconnect = sample(Neighborhood, min(len(Neighborhood), number))
        for eachServer in potentialconnect:
            if self.__NumofConnections < self.__MaxNumConn:
                if eachServer not in self.__ServerConnectionIPs:
                    servSock = Mytcpsocket()
                    ack1 = servSock.Connect2Server(eachServer)
                    ack2 = servSock.sendmsg(self.__Addr[1])
                    ack3 = servSock.recvmsg(BUFSIZ)  # receive ACK
                    if ack1 and ack2 and ack3 != 'closed':
                        self.__NumofConnections += 1
                        self.__ServerConnectionSocks.append(servSock)
                        self.__ServerConnectionIPs.append(eachServer)
                        t = MyThread(self.__download,
                                     (servSock, eachServer, videohash),
                                     self.__download.__name__)
                        t.start()
                        sleep(PROCESS_TIME)
                        self.__downloadthreads.append(t)
                    else:
                        self.__ServerNeighborhood.remove(eachServer)
            else:
                break
        self.__connectionLock.release()
        self.__neighborLock.release()

    def __userprompt(self, *args):
        while True:
            if self.__EXIT:
                return
            userinput = raw_input(
                '<<<Select a function>>>:\n[-1] Exit\n[1] Watch a Movie\n[2] Print Neighbors\n[3] Print Connections\nYour choice>> '
            )
            if userinput == '1':
                numofmovies = len(self.__avaiMovieList)
                if numofmovies == 0:
                    print 'No movies to watch yet!'
                    continue
                print '<<<Select a movie>>>:'
                print '#. <<Go back>>'
                print '0. <<Stop the current movie>>'
                for i, fname in enumerate(self.__avaiMovieList):
                    print repr(i + 1) + '. ' + fname
                input = raw_input('Your choice>> ')
                if input == '#':  # if the user wants to go back
                    pass
                elif input >= '0' and input <= str(numofmovies):
                    movieID = int(input) - 1
                    if movieID >= 0:  # watch a movie
                        for i, eachmovie in enumerate(self.__avaiMovieList):
                            if i == movieID:
                                videohash = hashlib.md5(eachmovie).hexdigest()
                                break
                    else:
                        videohash = 'None'  # stop watching the current movie
                    self.__movieInitialize(
                        videohash)  # initialize movie download and watching
            elif userinput == '2':
                self.__printAllNeighbors()
            elif userinput == '3':
                self.__printAllConnections()
            elif userinput == '-1':
                self.__EXIT = True
                return
            else:
                pass

    def __pruneconnections(self, tcpsock, Addr):
        self.__connectionLock.acquire()
        print tcpsock, Addr
        print self.__ServerConnectionSocks
        self.__ServerConnectionSocks.remove(tcpsock)
        self.__ServerConnectionIPs.remove(Addr)
        self.__NumofConnections -= 1
        self.__connectionLock.release()

    def __closeAllconnections(self):
        self.__connectionLock.acquire()
        for connection in self.__ServerConnectionSocks:
            connection.close()
        self.__ServerConnectionSocks = []
        self.__ServerConnectionIPs = []
        self.__NumofConnections = 0
        self.__connectionLock.release()

    def __printAllNeighbors(self):
        for eachNeighbor in self.__ServerNeighborhood:
            print eachNeighbor

    def __printAllConnections(self):
        for eachConnectionIP in self.__ServerConnectionIPs:
            print eachConnectionIP
        for eachConnectionSock in self.__ServerConnectionSocks:
            print eachConnectionSock