2016-10-12 5 views
0

LAN을 통해 TCP 파이썬 서버를 만들려고했지만이 프로젝트에서 계속 문제가 발생했습니다. 내 질문은 : 하나의 서버에서 여러 클라이언트에 (TCP를 통해) 메시지를 보낼 수 있습니까? (즉, client-1은 "Hello world"라는 메시지를 보내고 다른 모든 클라이언트 [clients-2, clients-3]에 메시지를 표시합니다. Heres는 지금까지 서버에 대한 내 코드 : 클라이언트에 대한파이썬 TCP 서버가 모든 클라이언트에게 메시지를 보내고 있습니다

import socket, time, sys 
import threading 

TCP_IP = input("Host IP: ") 
TCP_PORT = int(input("Host Port: ")) 
BUFFER_SIZE = 1024 

def createNewThread(function): 
    threading.Thread(target=function).start() 

def Listening(): 
    try: 
     while True: 
      s.listen(1) 

      conn,addr = s.accept() 
      threading.Thread(target=Listening).start() 
      print("User joined with IP %s" % (addr[0])) 
      while 1: 
       data = conn.recv(BUFFER_SIZE) 
       if not data: break 
       conn.send(addr[0].encode("utf-8") + b': ' + data) 
      conn.close() 
    except ConnectionResetError as e: 
     print("Connection was closed: ", e) 

try: 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.bind((TCP_IP,TCP_PORT)) 
    print("-----Server started-----") 
    Listening() 
except socket.error as e: 
    print("Socket error occured. More info: ", e) 

그리고 heres는 내 코드 : 모든 답변에 미리

import socket, sys, time 

TCP_IP = input("Connect to Local IP: ") 
TCP_PORT = int(input("Connect to Local Port: ")) 
BUFFER_SIZE = 1024 
running = True 

while running == True: 
    try: 
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     print("Connecting...") 
     s.connect((TCP_IP,TCP_PORT)) 
     print("Connected!") 
     while True: 
      MESSAGE = input("Message: ") 
      if MESSAGE == "exit": 
       s.close() 
       raise SystemExit 
      s.send(MESSAGE.encode('ascii')) 
      data = s.recv(BUFFER_SIZE) 
      print(data.decode("utf-8")) 

     running = False 
     time.sleep(20) 
    except: 
     print(sys.exc_info()[0]) 
     time.sleep(1) 

감사합니다!

편집 : 내가 OUPUT이 같은 것을보고 싶지 :

User3's IP: Message they sent 
User1's IP: Message they sent 
Message: What do you want to send? 
+0

"1 대의 서버에서 여러 클라이언트로 (TCP를 통해) 메시지를 보낼 수 있습니까?" - 예. 당신이 겪고있는 문제점은 무엇입니까? – Prabhu

+0

@Prabhu * 한숨 * 어떻게? –

답변

1

코드는 ... 아주 이상한이다. 우선, accept에 새 스레드를 만들고 클라이언트 대신 해당 스레드에 리스너를 보냅니다. 따라서 스레드는 절대로 죽지 않으며 메모리 및 CPU 누수가 발생합니다. 더 나쁜 것입니다. 코드에서 스레드 수는 수와 같습니다. 클라이언트는 이 서버에 연결되었습니다. 이것은 나쁘다.

def client(conn): 
    while True: 
     data = conn.recv(BUFFER_SIZE) 
     if not data: 
      break 
     conn.send(data) # simple ping 

def listener(): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.bind((TCP_IP, TCP_PORT)) 
    s.listen(5) 
    while True: 
     conn, addr = s.accept() 
     threading.Thread(target=client, args=(conn,)).start() 

if __name__ == '__main__': 
    listener() 

코드는 간단하고 짧은 더 메모리/CPU 누출이 없다 :

는 서버 측에서이보십시오.

이제 모든 클라이언트에 데이터를 전송합니다. 당신은 그들을 추적해야합니다. 당신은 클라이언트의 글로벌 딕셔너리 유지하여이 작업을 수행 할 수 있습니다 : 리스너 지금

CLIENTS = {} 

을 당신이 할 :

def client(conn): 
    while True: 
     data = conn.recv(BUFFER_SIZE) 
     if not data: 
      break 
     # broadcast 
     for client in CLIENTS.values(): 
      client.send(data) 

    # the connection is closed: unregister 
    del CLIENTS[conn.fileno()] 

그 코드 하나의 작은 문제가있다 :

def listener(): 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.bind((TCP_IP,TCP_PORT)) 
    s.listen(5) 
    while True: 
     conn, addr = s.accept() 
     # register client 
     CLIENTS[conn.fileno()] = conn 
     threading.Thread(target=client, args=(conn,)).start() 

및 클라이언트에서

(실제로는 여러 가지가 있습니다. 예를 들어 오류 처리). CLIENTS 사전을 통해 반복하는 동안 일부 클라이언트가 등록을 취소하면 어떻게됩니까? 파이썬은 예외를 던질 것이다. 간단한 솔루션은 삽입, 삭제 및 반복에 사전을 잠그는 것입니다.

다른 소켓이 이전 fileno()을 재사용하는 경우에도 경쟁 조건이 있습니다. 이 경우 수동으로 소켓에 대한 ID를 생성 할 수 있습니다 (바람직하게는 사용자 정의 클래스로 socket 객체를 래핑하여).

dict 대신 set을 사용할 수 있습니다. 그러나 어떤 시점에서는 특정 클라이언트 (msg로 식별)에 msg를 보내려고하기 때문에 결국에는 dict가 필요할 것입니다.

+0

내 코드가 이상하다는 것을 안다. 이런 종류의 것들에 관해서는별로 조직적이지 않다. 도움을 주셔서 감사합니다, 지금 모든 것을 시도해보십시오! –

+0

cpu 유출이란 무엇입니까? – Sam

+0

@Sam 메모리 누수와 같습니다. 리소스가 손실됩니다.cpu의 경우 이것은 무의미한 작업을 의미하므로 무언가를 의미있는 일을 할 수있는 사이클을 잃게됩니다. – freakish

관련 문제