1

server.py

import socket, select, signal, errno, os, sys
from threading import Thread

def broadcast_data (sock, message):
    for socket in CONNECTION_LIST:
        #use:
        #if socket != s and socket != sock:
        #if you want to broadcast to all but sending client and server
        # print sock.getpeername()[1]
        # print CLIENT_LIST[0][1]
        if socket != s:
            try :
                socket.send(message)
            except :
                #broken socket connection may be, chat client pressed ctrl+c for example
                socket.close()
                CONNECTION_LIST.remove(socket)


def handle_cli():
    #process client data
    data = sock.recv(RECV_BUFFER)
    if data == '?':
        broadcast_data(sock, hand_cl(CLIENT_LIST))
    elif data == 'removeme':
        hold = rem_cl(sock.getpeername()[1],CLIENT_LIST)
        CLIENT_LIST = hold
    elif data:
        broadcast_data(sock, "\r" + '<' + str(sock.getpeername()) + '> ' + data)
    else:
        sock.close()
        CONNECTION_LIST.remove(sock)

def hand_inter(signum, frame):
    print hand_cl(CLIENT_LIST)

def hand_qui(signum, frame):
    sys.exit(0)

def hand_cl(cl):
    totstring = "Current clients connected:"
    for c in cl:
        totstring+= " "+str(c)
    totstring+="\n"
    return totstring

def rem_cl(peername,cl):
    cl = [(ip, port) for ip, port in cl if port != peername]
    return cl



if __name__ == "__main__": 
    #keep track of socket descriptors
    signal.signal(signal.SIGINT, hand_inter)
    signal.signal(signal.SIGQUIT, hand_qui)
    CONNECTION_LIST = []
    CLIENT_LIST = []
    RECV_BUFFER = 4096
    HOST = 'localhost'
    PORT = int(sys.argv[1])
    ADDR = (HOST, PORT)
    if len(sys.argv) > 2:
        MAXHOST = int(sys.argv[2])
    else:
        MAXHOST = 2


    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind(ADDR)
    s.listen(MAXHOST)

    #add server socket to the list of readable connections
    CONNECTION_LIST.append(s)

    print "Chat server started on port " + str(PORT)
    while 1:
        #fix for signal interrupt
        while True:
            try:
                read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[])
            except select.error, v:
                if v[0] != errno.EINTR: raise
            else: break

        for sock in read_sockets:
            #if sock in read socks == new s, new connection
            if sock == s:
                sockfd, addr = s.accept()

                conmax = [MAXHOST, len(CONNECTION_LIST)]
                conmax = str(conmax)
                #send maxhost number for comparison
                sockfd.send(conmax)
                CONNECTION_LIST.append(sockfd)
                CLIENT_LIST.append(addr)

                print "Client (%s, %s) connected" % addr
                broadcast_data(sockfd, "[%s:%s] entered room\n" % addr)

            #else it's a message from a pre-connected client
            else:
                Thread(target=handle_cli).start()


    s.close()

Objective: Whenever a client sends message 'removeme', I want CLIENT_LIST to remove the specific client from the CLIENT_LIST. The method rem_cl works correctly and returns the correct results, however when I try to reassign CLIENT_LIST to the new updated list, I get the error:

line 26, in handle_cli
    hold = rem_cl(sock.getpeername()[1],CLIENT_LIST)
UnboundLocalError: local variable 'CLIENT_LIST' referenced before assignment

However if I remove CLIENT_LIST = hold I get no error.

How do I reassign CLIENT_LIST to be this newly returned list?

1 Answers1

0

In your function handle_cli(), when you attempt to assign a value to CLIENT_LIST, you are assigning it to a local variable (not a global variable). In order to assign that value to the global variable CLIENT_LIST that you are using in your script, you must first use the global statement:

global CLIENT_LIST
CLIENT_LIST = ...

The Python docs say, It would be impossible to assign to a global variable without global.

Also, check out the answer to the question use of "global" keyword in python.

Community
  • 1
  • 1
tsroten
  • 2,534
  • 1
  • 14
  • 17
  • Thanks for the correct answer. With regards to global, I shouldn't even be able to print CLIENT_LIST from within the function correct? If I declared CLIENT_LIST in the main scope, I should be able to reference from all subsequent function calls, shouldn't I? –  Mar 09 '14 at 15:58
  • You can reference global variables without using the ``global`` statement, but you cannot change their value. – tsroten Mar 09 '14 at 16:02