이전에 했던 1:1채팅에 이어서 로그인을 구현하려한다.
먼저 프로그램 실행순서를 간단하게 설명하면 먼저 서버와 연결된 후 클라이언트는 로그인을 거친다. 새로 아이디를 만드려면 create를 입력하고 사용할 아이디와 비밀번호를 입력하면 된다.
로그인을 하려면 아무키나 누르고 아이디와 비밀번호를 입력하면 된다.
서버측의 전체 코드부터 살펴보면,
이전 1:1채팅의 send와 receive를 사용하지만 제약을 두어 user_check가 되지 않으면 클라이언트에게 받은 메시지는 로그인과 새로운 아이디 생성을 위해서만 사용하고 출력되진 않는다. 이 후 로그인을 통해 유저 확인이 되면 user_check가 true로 설정되며 이전과 동일하게 1:1채팅을 사용할 수 있다. 코드가 좀 긴 관계로 코드 설명은 주석으로 하겠다.
from socket import *
import threading
import time
user_check = False
def send(sock):
while True:
sendData = input('>>> ')
sock.send(sendData.encode('utf-8'))
def receive(sock):
global seed, user_check
user_name = ""
while True:
if not user_check:
recvData = sock.recv(1024)
if recvData.decode('utf-8')[:6] == "create": # 사용자의 입력이 create이면
temp, id, password = recvData.decode('utf-8').split("/") # 입력을 split()을 통해 "/"로 나눈다
id_chk = False # (클라이언트쪽에서 입력을 "/"로 구분하여 보내므로 위의 각 변수에 담긴다)
id_count = 0 # valiation을 위한 count 변수(id는 알파벳이 필수로 들어가야하며 6자 이상)
for n in id: #
if n.isalpha(): #
id_chk = True #
id_count += 1 #
if id_chk and id_count >= 6: # valiation 조건을 통과하면 패스워드 설정단계로 넘어감
digit_count = 0 # 비밀번호의 valiation 조건은 숫자4개, 알파벳4개 이상
alpha_count = 0
for n in password: #
if n.isalpha(): #
alpha_count += 1
elif n.isdigit(): #
digit_count += 1
if alpha_count >= 4 and digit_count >= 4: # valiation 조건을 만족하면
seed[id] = password # seed에 아이디와 비밀번호 추가
else: #
sock.send("create fail".encode('utf-8'))
else: #
sock.send("create fail".encode('utf-8'))
else: # 아이디 생성이 아닌 로그인을 시도했을 때(create가 아닌 아무 문자열을 입력받았을 때)
id, password = recvData.decode('utf-8').split("/") #마찬가지로 "/"로 id와 password구분
if id in seed: # 만약 입력받은 아이디가 seed에 있을 때
if seed[id] == password: # 입력받은 비밀번호가 seed의 비밀번호와 동일할 때
sendData = "Success" #
sock.send(sendData.encode('utf-8'))
user_check = True # 이때 유저를 확인했으므로 user_check = true
user_name = id #
else: # 비밀번호에서 실패시 비밀번호가 틀렸다고 알림
sock.send("wrong password!".encode('utf-8'))
else: # 아이디가 없을 시 아이디가 틀렸다고 알림
sock.send("wrong id!".encode('utf-8'))
else: # user_check가 되었을 때 정상적으로 메시지를 주고 받음
recvData = sock.recv(1024)
print(f'{user_name} :', recvData.decode('utf-8'))
port = 8081
seed = {"client1": "client1234", "client2": "client1234", "client3": "client1234", "client4": "client1234", "client5": "client1234"}
serverSock = socket(AF_INET, SOCK_STREAM)
serverSock.bind(('', port))
serverSock.listen(1)
print(f'Waiting for connection to port {port}')
connectionSock, addr = serverSock.accept()
print(f'Connected on port {addr}')
sender = threading.Thread(target=send, args=(connectionSock,))
receiver = threading.Thread(target=receive, args=(connectionSock,))
sender.start()
receiver.start()
while True:
time.sleep(1)
pass
클라이언트의 코드도 살펴보자.
서버의 코드와 다른점은 서버는 receive에 주력했지만 클라이언트의 코드는 send에 주력한다.
아이디를 생성하려면 create를 입력하고, 로그인을 하려면 아무키나 입력하면 된다.
from socket import *
import threading
import time
login_check = False # 로그인을 했는지 체크
def send(sock):
while True:
time.sleep(0.1) # 로그인을 했을 때 서버측에서 확인하고 조치를 취하는데 걸리는 시간이 필요
if not login_check:
t = input("아이디를 새로 만드시려면 create를, 로그인 하려면 아무키를 입력해주세요 ")
if t == "create" : # 유저가 create를 입력하면 새로운 id와 pw를 받는다
id = input("new id: ")
password = input("new password: ")
user_info = t + "/" + id + "/" + password # 사용자의 입력을 "/"로 구분하여 저장하고
sock.send(user_info.encode('utf-8')) # 이 값을 서버에게 보냄
else: # 생성이 아닌 로그인을 시도했을 시
id = input('id: ')
password = input('password: ')
sendData = id + "/" + password
sock.send(sendData.encode('utf-8'))
else: # 이후 정상적으로 채팅 가능
sendData = input('>>> ')
sock.send(sendData.encode('utf-8'))
def receive(sock):
global login_check
while True:
recvData = sock.recv(1024)
if not login_check: # 아직 로그인을 하지 않았을 때는 서버에게 로그인 확인을 받아야함
if recvData.decode('utf-8') == "Success": # 서버에게 확인받으면
login_check = True # 로그인 체크
elif recvData.decode('utf-8') == "wrong id!" or recvData.decode('utf-8') == "wrong password!" or recvData.decode('utf-8') == "create fail":
print(recvData.decode('utf-8')) # 로그인 실패했을 시 서버에게 받은 값을 출력
else:
print('Server :', recvData.decode('utf-8'))
port = 8081
clientSock = socket(AF_INET, SOCK_STREAM)
clientSock.connect(('127.0.0.1', port))
print('Connection success!')
sender = threading.Thread(target=send, args=(clientSock,))
receiver = threading.Thread(target=receive, args=(clientSock,))
sender.start()
receiver.start()
while True:
time.sleep(1)
pass
실행 결과
이렇게 간단하게 1:1 채팅 기능에 로그인까지 추가해보았다!
소켓프로그래밍 생각보다 재밌네요 ㅎㅎ
아 그리고 서버측의 코드를 먼저 실행해주어야 오류가 안뜹니다!