
ECHO 서버와 큰 차이점은 클라이언트를 지속적으로 받기 위하여 accept가 반복문 안으로 들어가게 됩니다.
이후 클라이언트의 데이터를 송신 및 수신을 위한 스레드를 생성하여 비동기적으로 클라이언트가 채팅을 할 수 있게 합니다.
스레드에서는 데이터를 송신한 클라이언트를 제외한 모든 클라이언트에게 데이터를 전송합니다.
import socket
import threading
HOST = ""
PORT = 9999
CLIENTS = []
def work(_client_socket:socket.socket, _remote_addr:tuple):
user = f"{_remote_addr[0]}:{_remote_addr[1]}"
print(f"[{user}] Connected")
while True:
try:
data = _client_socket.recv(1024)
except ConnectionError:
print(f"[{user}] Disconnected")
CLIENTS.remove(_client_socket)
break
if not data:
break
data = f"[{user}] {data.decode()}"
print(data)
# 모든 소켓을 순환
for client in CLIENTS:
# 데이터를 송신한 클라이언트가 아니라면 데이터를 송신
if client != _client_socket:
client.sendall(data.encode())
server_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen()
while True:
try:
client_socket, remote_addr = server_socket.accept()
except KeyboardInterrupt:
break
# 클라이언트에 할당된 소켓을 리스트에 추가
CLIENTS.append(client_socket)
# 클라이언트로부터 데이터 송신 및 수신을 수행할 스레드 생성
client_thread = threading.Thread(target=work, args=(client_socket, remote_addr))
client_thread.daemon = True
client_thread.start()
print("Server stop")
for client in CLIENTS:
client.close()
server_socket.close()
지정된 서버로 접속 후 데이터를 전송합니다.
exit을 입력하기 전까지는 계속 데이터를 송신할 수 있습니다.
데이터 수신은 비동기적으로 이루어지기 때문에 송신과 분리된 스레드를 이용합니다.
import socket
import threading
def work(socket:socket.socket):
while True:
try:
data = socket.recv(1024)
except ConnectionAbortedError:
break
except ConnectionResetError:
break
if not data:
break
print(data.decode())
HOST = "127.0.0.1"
PORT = 9999
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))
thread = threading.Thread(target=work, args=(client_socket,))
thread.start()
while True:
data = input("message > ")
if data == "exit":
break
try:
client_socket.sendall(data.encode())
except ConnectionResetError:
print("Server die")
break
client_socket.close()
thread.join()