用Python创建一个简单的聊天应用程序(套接字)
我正在尝试使用套接字(python)创建一个简单的聊天应用程序。其中,客户端可以向服务器发送消息,服务器只需将消息广播给所有其他客户端(发送消息的客户端除外) 客户端有两个线程,它们永远运行用Python创建一个简单的聊天应用程序(套接字),python,multithreading,sockets,synchronization,chat,Python,Multithreading,Sockets,Synchronization,Chat,我正在尝试使用套接字(python)创建一个简单的聊天应用程序。其中,客户端可以向服务器发送消息,服务器只需将消息广播给所有其他客户端(发送消息的客户端除外) 客户端有两个线程,它们永远运行 send:send只是将cleints消息发送到服务器 receive:从服务器接收消息 服务器还有两个线程,它们将永远运行 accept\u cleint:接受来自客户端的传入连接 broadcast\u usr:接受来自客户端的消息并将其广播到所有其他客户端 但是我得到了错误的输出(请参考下图)。所有线
send
:send只是将cleints消息发送到服务器
receive
:从服务器接收消息
服务器还有两个线程,它们将永远运行
accept\u cleint
:接受来自客户端的传入连接
broadcast\u usr
:接受来自客户端的消息并将其广播到所有其他客户端
但是我得到了错误的输出(请参考下图)。所有线程都假定一直处于活动状态,但有时客户端可以发送消息,有时则不能。比如说Tracey发了4次“hi”,但没有广播,当John说了2次“bye”,然后1次信息被广播。服务器上似乎有一些线程同步问题,我不确定。请告诉我怎么了
下面是代码
chat_client.py
import socket, threading
def send():
while True:
msg = raw_input('\nMe > ')
cli_sock.send(msg)
def receive():
while True:
sen_name = cli_sock.recv(1024)
data = cli_sock.recv(1024)
print('\n' + str(sen_name) + ' > ' + str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5023
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
uname = raw_input('Enter your name to enter the chat > ')
cli_sock.send(uname)
thread_send = threading.Thread(target = send)
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
chat_server.py
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
uname = cli_sock.recv(1024)
CONNECTION_LIST.append((uname, cli_sock))
print('%s is now connected' %uname)
def broadcast_usr():
while True:
for i in range(len(CONNECTION_LIST)):
try:
data = CONNECTION_LIST[i][1].recv(1024)
if data:
b_usr(CONNECTION_LIST[i][1], CONNECTION_LIST[i][0], data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, sen_name, msg):
for i in range(len(CONNECTION_LIST)):
if (CONNECTION_LIST[i][1] != cs_sock):
CONNECTION_LIST[i][1].send(sen_name)
CONNECTION_LIST[i][1].send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
thread_bs = threading.Thread(target = broadcast_usr)
thread_bs.start()
好吧,我之前在评论中撒了谎,对不起。问题实际上是服务器上的
broadcast\u usr()
函数。它在recv()
方法中阻塞,并阻止除当前所选用户之外的所有用户在通过for
循环时一次讲话。为了解决这个问题,我修改了server.py程序,为它接受的每个客户端连接生成一个新的broadcast_usr线程。我希望这有帮助
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
uname = cli_sock.recv(1024)
CONNECTION_LIST.append((uname, cli_sock))
print('%s is now connected' %uname)
thread_client = threading.Thread(target = broadcast_usr, args=[uname, cli_sock])
thread_client.start()
def broadcast_usr(uname, cli_sock):
while True:
try:
data = cli_sock.recv(1024)
if data:
print "{0} spoke".format(uname)
b_usr(cli_sock, uname, data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, sen_name, msg):
for client in CONNECTION_LIST:
if client[1] != cs_sock:
client[1].send(sen_name)
client[1].send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
#thread_bs = threading.Thread(target = broadcast_usr)
#thread_bs.start()
我试着避开你说的“阿提尼什”这只虫子。客户端将被询问一次用户名,此“uname”将包含在要发送的数据中。请参阅我对“发送”函数所做的操作 为了便于可视化,我在所有收到的消息中添加了一个“\t”
import socket, threading
def send(uname):
while True:
msg = raw_input('\nMe > ')
data = uname + '>' + msg
cli_sock.send(data)
def receive():
while True:
data = cli_sock.recv(1024)
print('\t'+ str(data))
if __name__ == "__main__":
# socket
cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# connect
HOST = 'localhost'
PORT = 5023
uname = raw_input('Enter your name to enter the chat > ')
cli_sock.connect((HOST, PORT))
print('Connected to remote host...')
thread_send = threading.Thread(target = send,args=[uname])
thread_send.start()
thread_receive = threading.Thread(target = receive)
thread_receive.start()
您还必须相应地修改服务器代码
server.py
import socket, threading
def accept_client():
while True:
#accept
cli_sock, cli_add = ser_sock.accept()
CONNECTION_LIST.append(cli_sock)
thread_client = threading.Thread(target = broadcast_usr, args=[cli_sock])
thread_client.start()
def broadcast_usr(cli_sock):
while True:
try:
data = cli_sock.recv(1024)
if data:
b_usr(cli_sock, data)
except Exception as x:
print(x.message)
break
def b_usr(cs_sock, msg):
for client in CONNECTION_LIST:
if client != cs_sock:
client.send(msg)
if __name__ == "__main__":
CONNECTION_LIST = []
# socket
ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# bind
HOST = 'localhost'
PORT = 5023
ser_sock.bind((HOST, PORT))
# listen
ser_sock.listen(1)
print('Chat server started on port : ' + str(PORT))
thread_ac = threading.Thread(target = accept_client)
thread_ac.start()
服务器端发生的变化是:连接的用户和发言的用户不再被看到。如果你的目的是联系客户,我不知道这是否意味着什么。如果您想通过服务器严格监控客户端,可能还有另一种方法。我认为问题在于您的客户端线程循环,尽管您的服务器也需要能够处理客户端断开连接。仅供参考,Twisted是一个用于制作线程服务器的Python库。您的代码运行良好,但存在一个小错误。发送者必须发送2条消息才能广播。客户端的
sen\u name=cli\u sock.recv(1024)
和data=cli\u sock.recv(1024)
都在接收发送方名称和消息。请参考下面的屏幕截图,服务器代码第17行有缩进错误。它只需要向左移动1个字符。