几天前做了个实验,使用python socket 实现多人在线聊天
要求:1.使用socket搭建聊天服务器端,允许多客户端接入
2.使用socket 搭建聊天客户端
3.实现一对一聊天
服务器
import socket
import time
import select
import datetime
skt_dict = dict()
now = datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m-%d %H:%M:%S')
class User(object):
"""docstring for User"""
def __init__(self, skt, nick_name, addr):
super(User, self).__init__()
self.skt = skt
self.nick_name = nick_name
self.addr = addr
def connect_in(self):
print("new user::"+self.nick_name+"--"+str(self.addr[0])+":"+str(self.addr[1]))
def print_name(self):
print(self.nick_name)
def parse_cmd(cmd_char,user):
# to parse cmd char
# distinguish different cmd and react
if cmd_char.find("online"):
str_to_send = ""
for v in skt_dict.values():
str_to_send += v.nick_name+","
str_to_send = "users online:" + str_to_send
user.skt.send(str_to_send.encode("utf-8"))
if cmd_char.find("room"):
pass
def parse_talk(data,user):
# to deal with talk
# only talk to the people
# data formation : [0]->None [1]->talkto [2]->msg
data_list = data.split("/!/")
for v in skt_dict.values():
if v.nick_name == data_list[1]:
msg_to_send = "【Private】"+user.nick_name+"("+now+"):"+data_list[2]
v.skt.send(msg_to_send.encode("utf-8"))
def main():
print("server running...")
tcp_skt = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_skt.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
tcp_skt.bind(("",7789))
tcp_skt.listen(128)
# create epoll variable
epl = select.epoll()
epl.register(tcp_skt.fileno(),select.EPOLLIN)
while True:
epoll_list = epl.poll()
for fd,event in epoll_list:
if fd == tcp_skt.fileno():
# listen socket has someone linked in
new_skt,client_addr = tcp_skt.accept()
cli_nick_name = new_skt.recv(1024).decode("utf-8")
user = User(new_skt,cli_nick_name,client_addr)
epl.register(new_skt.fileno(),select.EPOLLIN)
skt_dict[new_skt.fileno()] = user
user.connect_in()
elif event == select.EPOLLIN:
# other socket have msg in
data = skt_dict[fd].skt.recv(1024).decode("utf-8")
if data:
if data.find("~-")!=-1:
# now data is cmd char
parse_cmd(data,skt_dict[fd])
elif data.find("~:/!/")!=-1:
parse_talk(data,skt_dict[fd])
elif data.find("~?")!=-1:
new_id = data.split("?")[1]
skt_dict[fd].nick_name = new_id
else:
data_to_send = "【Broadcast】"+skt_dict[fd].nick_name+"("+now+"):"+data
for v in skt_dict.values():
if v.nick_name != skt_dict[fd].nick_name:
v.skt.send(data_to_send.encode("utf-8"))
else:
skt_dict[fd].skt.close()
print("quit::"+skt_dict[fd].nick_name)
del skt_dict[fd]
if __name__ == '__main__':
main()
客户端:
import socket
import time
import threading
import os
def connect_to_server(cli_skt):
dst_ip = str(input("server ip:"))
try:
cli_skt.connect((dst_ip,7789))
except Exception as e:
print("something wrong occurs...try again..")
# print(str(e))
connect_to_server(cli_skt)
else:
nick_name = input("your nick name:")
cli_skt.send(nick_name.encode("utf-8"))
def get_commend(cli_skt):
while True:
print("commend list: -online -chat -exit -brdcst -cgId")
cmd_char = input("please input commend :")
if cmd_char == "-exit" :
print("this program will close in 5 seconds")
for i in range(5):
print(str(5-i)+"...")
time.sleep(1)
break
elif cmd_char == "-online":
check_online(cli_skt)
continue
elif cmd_char == "-brdcst":
broadcast(cli_skt)
elif cmd_char == "-cgId":
new_id = input("your new id:")
cgid_to_send = "~?"+new_id
try:
cli_skt.send(cgid_to_send.encode("utf-8"))
except Exception as e:
print(str(e))
else:
print("Id has changed")
elif cmd_char == "-chat":
talkto = input("who to talk :")
talk(cli_skt,talkto)
elif cmd_char == "-room":
check_room(cli_skt)
else :
print("invalid input ,try again")
continue
def check_room(cli_skt):
check_room_cmd = "~-room"
try:
cli_skt.send(check_room_cmd.encode("utf-8"))
except Exception as e:
pass
try:
response = cli_skt.recv(1024).decode("utf-8")
except Exception as e:
pass
else:
print(response)
def check_online(cli_skt):
# check online users
check_online_cmd = "~-online"
# send a check online request
try:
cli_skt.send(check_online_cmd.encode("utf-8"))
except Exception as e:
pass
# receive the server response
try:
response = cli_skt.recv(1024).decode("utf-8")
except Exception as e:
pass
else:
print(response)
def talk(cli_skt,talkto):
# data formation : [0]->~: [1]->talkto [2]->msg
try:
while True:
input_msg = input()
if input_msg == "exit":
break
msg_to_send = "~:/!/"+talkto+"/!/"+input_msg
cli_skt.send(msg_to_send.encode("utf-8"))
except Exception as e:
print("input error")
print(str(e))
def broadcast(cli_skt):
while True:
msg = input()
if msg == "exit":
break
else:
try:
cli_skt.send(msg.encode("utf-8"))
except Exception as e:
print("broadcast error")
print(str(e))
def recv_msg(cli_skt):
print("you are in broadcast channel")
while True:
try:
print("\n---"+cli_skt.recv(1024).decode("utf-8"))
except Exception as e:
continue
# print("no recv")
# print(str(e))
def main():
cli_skt = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
cli_skt.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
connect_to_server(cli_skt)
cli_skt.setblocking(False)
t = threading.Thread(target = recv_msg,args = (cli_skt,))
t.start()
get_commend(cli_skt)
os._exit(0)
if __name__ == '__main__':
main()
服务器使用epoll单进程单线程,客户端两线程。