2016-03-20 4 views
0

のために待機していないことは、サーバーのコードです - ここソケットはここで、複数の要求

import socket, select,re 


def getSocket(idd): 
    return CONNECTION_LIST[idd] 


def broadcast_data (sock, message): 
    for socket in CONNECTION_LIST: 
     if socket != server_socket and socket != sock : 
      try : 
       socket.send(message) 
      except : 
       socket.close() 
       CONNECTION_LIST.remove(socket) 


def single_client (sock , message , idd): 
    socket = getSocket (idd) 
    if socket : 
    socket.send(message) 
    else: 
    print "chudap" 


if __name__ == "__main__": 

    CONNECTION_LIST = [] 
    RECV_BUFFER = 4096 
    PORT = 5000 
    PORTC = 2225 

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    server_socket.bind(("0.0.0.0", PORT)) 
    server_socket.listen(10) 

    listen = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
    listen.bind(("0.0.0.0" , PORTC)) 
    #listen.listen(10) 

    CONNECTION_LIST.append(server_socket) 
    CONNECTION_LIST.append(listen) 
    print "Chat server started on port " + str(PORT) 

    idd = 1 
    while 1: 
     # Get the list sockets which are ready to be read through select 
     read_sockets,write_sockets,error_sockets = select.select(CONNECTION_LIST,[],[]) 

     for sock in read_sockets: 
      if sock == server_socket: 
       sockfd, addr = server_socket.accept() 
       CONNECTION_LIST.append(sockfd) 
       #name = sockfd.recv(RECV_BUFFER) 
       print "connected from ip %s, id assigned is %d" % (addr[0] , idd) 
       broadcast_data(sockfd, "client with IP %s has entered with id = %d\n" % (addr[0] , idd)) 
       idd += 1 
      elif sock == listen: 
       print "debugging" 
       data,addr = listen.recvfrom(RECV_BUFFER) 
       print "Received server probe request from [%s:%s]"%addr 
       listen.sendto("iam" , addr)#(addr[0] , 2624)) 
       listen.close() 
       CONNECTION_LIST.remove(listen) 
       listen = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
       listen.bind(("0.0.0.0" , PORTC)) 
       CONNECTION_LIST.append(listen) 
      else: 
       try: 
        data = sock.recv(RECV_BUFFER) 
        if re.findall(r'.*/msg\d+' , data): 
         #print "got single client message request" + data 

         name = "private message from " + re.findall('([^:]+): /msg(\d+)([^"]+)' , data)[0][0] + ": " 
         #print name 

         eid = int(re.findall('([^:]+): /msg(\d+)([^"]+)' , data)[0][1]) 
         #print eid 

         data = re.findall('([^:]+): /msg(\d+)([^"]+)' , data)[0][2] 
         #print data 

         data = name + data 

         #print "single client message sent with id = %d" %eid 

         single_client(sock , data , int(eid)) 
        elif data: 
         broadcast_data(sock, data) 

       except: 
        broadcast_data(sock, "Client (%s, %s) is offline" % addr) 
        print "Client (%s, %s) is offline" % addr 
        sock.close() 
        CONNECTION_LIST.remove(sock) 
        continue 

    server_socket.close() 

は、クライアントのコードです -

import socket, select, string, sys 

def prompt() : 
    sys.stdout.write('<You>: ') 
    sys.stdout.flush() 

def exit(sock): 
    print "\n Thank you for using chat application\nBye" 
    sock.close() 
    sys.exit() 

def printUsage(): 
    print "1. By default your message will be sent to all clients sitting on the chat server" 
    print "2. You can send a private message to a person by starting your message as \"/msg{id}{Your message}\" for example /msg2Hi will send \"hi\" to client with id 2" 
    print "3. For quitting simply type \"/q\" or \"/quit\"" 
    prompt() 

PORTS = 2225 
PORTC = 2624 


if __name__ == "__main__": 


    broad = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 
    broad.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) 
    broad.bind(('0.0.0.0' , 2624)) 
    broad.sendto(b'whoisserver', 0, ("255.255.255.255", PORTS)) 
    broad.settimeout(10) 
    print 15*"-" + "WELCOME TO CHATVILLE" + 15*"-" + "\nFinding the server" 
    try: 
     data , addr = broad.recvfrom(10) 
    except: 
     print "Can't find server ! Please ensure that server is up" 
     broad.close() 
     sys.exit() 
    broad.close() 


    if data <> "iam": 
     print "Can't find a valid server !" 
     sys.exit() 
    host = addr[0] 
    port = 5000 
    print addr 


# host = sys.argv[1] 
# port = int(sys.argv[2]) 
# print host,port 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.settimeout(2) 

    name = raw_input("Please Enter your name: ") 
    try : 
     s.connect((host, port)) 
     s.send(name) 
    except : 
     print 'Unable to connect' 
     sys.exit() 

    print 'Connected to remote host. Enjoy...............................' 
    name = "<" + name + ">" + ": " 
    print " - type /h to see usage instructions any time :) - " 
    prompt() 

    while 1: 
     socket_list = [sys.stdin, s] 

     read_sockets, write_sockets, error_sockets = select.select(socket_list , [], []) 

     for sock in read_sockets: 
      if sock == s: 
       data = sock.recv(4096) 
       if not data : 
        print '\nDisconnected from chat server' 
        sys.exit() 
       else : 
        print "" 
        sys.stdout.write(data) 
        prompt() 

      else : 
       msg = sys.stdin.readline() 
       if str.startswith(msg, "/h") or str.startswith(msg,"/help"): 
        printUsage() 
       elif str.startswith(msg, "/quit") or str.startswith(msg,"/q"): 
        exit(s) 
       else: 
        msg = name + msg 
        s.send(msg) 
        prompt() 

主な問題は、1つのクライアントだけのように接続することができるということですすぐに最初のクライアントがサーバーに接続すると、他のクライアントはそのサーバーを検出できません。

私はtcpdumpのにより、クライアントのコードを見て、試してみました私は、パケットは、ポート番号2225で起こって見ることができますが、ソケットが最初に接続した後、全く応答しません聞きます。

PS - 以前私はの聴き取りをソケットに何度も繰り返していましたが、これも試してみましたが、うまくいかなかったのです。

答えて

1

broadcast_data()では、書き込むソケットからUDPソケット(listen)を除外しないので、そのソケットでsend()を呼び出します。何のアドレスが供給されていない(とsocket.send()とすることはできません)ので、これは例外

socket.error: [Errno 89] Destination address required 

で失敗します。例外ハンドラはUDPソケットを閉じ、新しいクライアントからのメッセージはそれ以上受信できません。そのため、追加のクライアントはサーバーに接続できません。

これは、裸の例外、つまりすべての例外を処理する例外文を使用することはお勧めできません。この場合、ハンドラは事実を記録することなくUDPソケットを閉じます。あなたのコードには、他にも例外がある文があります。この種のバグを避けるために、特定の例外を処理することをお勧めします。あなたは無視するソケットのリストにUDPソケットを追加することによって、それを修正することができます:

def broadcast_data(sock, message): 
    for socket in CONNECTION_LIST: 
     if socket not in (server_socket, sock, listen): 
      try : 
       socket.send(message) 
      except socket.error as exc: 
       print '!!! An error occurred while writing to client. !!!' 
       print exc 
       socket.close() 
       CONNECTION_LIST.remove(socket) 

今試みは、UDP listenソケットにメッセージを送信するために行われないと、ソケットがエラーのために閉鎖されることはありません。

P.S. listenソケットを閉じて再び開くメインループのコードは必要ありません。

+0

うわー!文字通りうわー、私の心はこの問題がここで起きるとは考えなかった。ありがとう:) –

関連する問題