Python实现多用户全双工聊天(一对一)

多用户全双工聊天简陋版

简单实现了两个客户端之间的通信,客户端发送消息,先由服务器接收,然后服务器转发到另一客户端。

该版本功能非常简陋,仅仅实现了最简单的聊天,有很多地方需要注意。

工作步骤:

  • 服务器端运行
  • 一个客户端运行,连接成功后输入用户名,服务器会保存该用户名在一个字典中,字典的对应关系是 username --> socket
  • 输入用户名之后,该客户端需要确定一个聊天用户,客户端输入To:user即可;如果客户端发送其他文本的话,会收到来自服务器的提示:“Nobody is chatting with you. Maybe the one talked with you is talking with someone else”
  • 当两个客户端成功连接之后就可以互相发送消息

服务器端代码如下:

#!/usr/bin/python
#coding:utf-8
#server.py
from socket import *
from time import ctime
import threading
import re

HOST = ‘‘
PORT = 9999
BUFSIZ = 1024
ADDR = (HOST,PORT)

tcpSerSock = socket(AF_INET,SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)

clients = {} # username -> socket
chatwith = {} # user1.socket -> user2.socket

# clients字典中记录了连接的客户端的用户名和套接字的对应关系
# chatwith字典中记录了通信双方的套接字的对应

# messageTransform()处理客户端确定用户名之后发送的文本
# 文本只有四种类型:
#   None
#   Quit
#   To:someone
#   其他文本
def messageTransform(sock,user):
    while True:
        data = sock.recv(BUFSIZ)
        if not data:
            if chatwith.has_key(sock):
                chatwith[sock].send(data)
                del chatwith[chatwith[sock]]
                del chatwith[sock]
            del clients[user]
            sock.close()
            break
        if data==‘Quit‘:
            sock.send(data)
            if chatwith.has_key(sock):
                data = ‘%s.‘ % data
                chatwith[sock].send(data)
                del chatwith[chatwith[sock]]
                del chatwith[sock]
            del clients[user]
            sock.close()
            break
        elif re.match(‘^To:.+‘, data) is not None:
            data = data[3:]
                if clients.has_key(data):
                if data==user:
                        sock.send(‘Please don\‘t try to talk with yourself.‘)
                else:
                        chatwith[sock] = clients[data]
                        chatwith[clients[data]] = sock
                else:
                sock.send(‘the user %s is not exist‘ % data)
        else:
            if chatwith.has_key(sock):
                chatwith[sock].send(‘[%s] %s: (%s)‘ % (ctime(),user,data))
            else:
                sock.send(‘Nobody is chating with you. Maybe the one talked with you is talking with someone else‘)

# 每个客户端连接之后,都会启动一个新线程
# 连接成功后需要输入用户名
# 输入的用户名可能会:
#   已存在
#   (客户端直接输入ctrl+c退出)
#   合法用户名
def connectThread(sock,test): # client‘s socket

    user = None
    while True: # receive the username
        username = sock.recv(BUFSIZ)
        if not username: # the client logout without input a name
            print(‘The client logout without input a name‘)
            break
        if clients.has_key(username): # username existed
            sock.send(‘Reuse‘)
        else: # correct username
            sock.send(‘OK‘)
            clients[username] = sock # username -> socket
            user = username
            break
    if not user:
        sock.close()
        return
    print(‘The username is: %s‘ % user)
    # get the correct username

    messageTransform(sock,user)

if __name__==‘__main__‘:
    while True:
        print(‘...WAITING FOR CONNECTION‘)
        tcpCliSock, addr = tcpSerSock.accept()
        print(‘CONNECTED FROM: ‘, addr)
        chat = threading.Thread(target = connectThread, args = (tcpCliSock,None))
        chat.start()

客户端代码如下:

#!/usr/bin/python
#coding:utf-8
#client.py
from socket import *
from time import ctime
# from termios import tcflush,TCIFLUSH
import threading
import sys

HOST = ‘127.0.0.1‘
PORT = 9999
BUFSIZ = 1024
ADDR = (HOST,PORT)

tcpCliSock = socket(AF_INET,SOCK_STREAM)
tcpCliSock.connect(ADDR)
‘‘‘
因为每个客户端接收消息和发送消息是相互独立的,
所以这里将两者分开,开启两个线程处理
‘‘‘
def Send(sock,test):
    while True:
    try:
        data = raw_input()
        sock.send(data)
        if data==‘Quit‘:
            break
    except KeyboardInterrupt:
        sock.send(‘Quit‘)
        break

def Recv(sock,test):
    while True:
    data = sock.recv(BUFSIZ)
    if data==‘Quit.‘:
        print(‘He/She logout‘)
        continue
    if data==‘Quit‘:
        break
    print(‘         %s‘ % data)

if __name__==‘__main__‘:
    print(‘Successful connection‘)
    while True:
        username = raw_input(‘Your name(press only Enter to quit): ‘)
        tcpCliSock.send(username)
        if not username:
            break
        # username is not None
        response = tcpCliSock.recv(BUFSIZ)
        if response==‘Reuse‘:
            print(‘The name is reuse, please set a new one‘)
            continue
        else:
            print(‘Welcome!‘)
            break

    if not username:
        tcpCliSock.close()

    recvMessage = threading.Thread(target = Recv, args = (tcpCliSock,None))
    sendMessage = threading.Thread(target = Send, args = (tcpCliSock,None))
    sendMessage.start()
    recvMessage.start()
    sendMessage.join()
    recvMessage.join()

总结:

功能简陋,后续会有所改进。这里还有很多地方需要注意。

比如说两个客户端A成功连接后,和客户端B聊天。A发送消息时直接输入ctrl+c退出程序(sendMessage线程会结束),我将这种情况模拟成A发送Quit登出。服务器接收到A登出信息之后,会回发一个Quit给A,A成功登出(recvMessage线程结束)。此外如果A和B建立了聊天关系,就要接触这个关系,服务器发送Quit.给B,B会继续接收信息,但是服务器端的chatwith字典中已经不存在A.socket --> B.socket关系。

但是还有很多没有解决的问题,比如说客户端A并没有输入信息,直接点击关闭按钮退出,就会发生异常(与之聊天的B客户端会崩溃)。

如果当前存在 A-->B的聊天关系,这时有一个C登录,并且确定了C-->A的聊天关系,那么A会和C聊天,这时客户端B就会被挂起。

主要的问题还是在于客户端非正常登出时的应对,目前解决了一部分问题,但是应该还有不少缺陷。

时间: 2024-10-22 21:08:51

Python实现多用户全双工聊天(一对一)的相关文章

Python写的简陋版一对一聊天工具,全双工

好该睡觉了,明天还要上班~~~直接上代码,后面再总结 1 import threading 2 import os 3 import socket 4 5 6 def RecvProcess ( UDP_Socket, LocalAddrInfo ): 7 print 'UDP Recver is UP' 8 while 1: 9 data, PeerAddr = UDP_Socket.recvfrom ( 1024 ) 10 if data == 'local exit' and LocalA

Python简单全双工聊天器

服务器: 1 #!/usr/bin/python 2 #enconding:utf-8 3 import sys 4 import socket 5 import select 6 import time 7 8 HOST='' 9 PORT=21234 10 ADDR=(HOST,PORT) 11 BUFSIZ=8096 12 13 SerSock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) 14 SerSock.setsockopt(so

如何优雅的用Python玩转语音聊天机器人

一名极客运维人员,走在脑洞大开的路上.... Python聊天机器人:可以感应人是否存在,识别语音,通过图灵API语音回答 -------------------------上图镇楼---------------------------- [详细攻略] 所需硬件: 树莓派B+ 人体红外线感应模块 内置麦克风摄像头(实测树莓派免驱淘宝链接) 申请API: 百度语音api 图灵api 语音聊天机器人实现原理:当有人来到跟前时-->触发聊天功能,开始以每2s检测录制语音-->通过百度语音api合成文

python 开发简单的聊天工具-乾颐堂

python 太强大了,以至于它什么都可以做,哈哈,开个玩笑.但是今天要讲的真的是一个非常神奇的应用. 使用python写一个聊天工具 其实大家平时用的QQ类似的聊天工具,也是使用socket进行聊天,只是它还包含了更加复杂的功能.基本原理是一样的. python实现聊天功能,主要用到了socket模块.下面直接上实例吧 server端 1 2 3 4 5 6 7 8 9 10 11 12 13 import socket s=socket.socket() #建立socket链接 s.bind

python 开发简单的聊天工具

python 太强大了,以至于它什么都可以做,哈哈,开个玩笑.但是今天要讲的真的是一个非常神奇的应用. 使用python写一个聊天工具 其实大家平时用的QQ类似的聊天工具,也是使用socket进行聊天,只是它还包含了更加复杂的功能.基本原理是一样的. python实现聊天功能,主要用到了socket模块.下面直接上实例吧 server端 1 2 3 4 5 6 7 8 9 10 11 12 13 import socket s=socket.socket() #建立socket链接 s.bind

python socket 多人聊天室

参考来源(其实我从上面复制了一点):Python 的 Socket 编程教程  http://www.oschina.net/question/12_76126Python线程指南 http://www.open-open.com/lib/view/open1345476194313.html Python Socket文档 https://docs.python.org/3/library/socket.html#socket-objects 具体思路:每个client有两个线程,分别负责接收

利用Python来写一个聊天工具!可能下个QQ或者微信会是你开发的?

用到的库 socket库 进群:548377875 即可获取数十套PDF哦! 先看代码! TCP服务端 TCP客户端 '电话'接通后对方就会开始'说话'(发送了消息),接收消息了recv是接收信息,1024这里需要解释一下,是接收的最大字节(接收到的内容为二进制).但是细心的读者可能发现了,用send发送的时候并没有设置发送的字节,其实可以更大,最大不要超过8K就可以了.下面解释这个怎么用才能更好. 接收消息了还需要发送信息.发送信息只需要用send就可以发了,但是需要发送二进制的内容. 另外一

python使用udp实现聊天器

聊天器简易版 使用udp实现一个简单的聊天器程序,要求如下: 在一个电脑中编写1个程序,有2个功能 1.获取键盘数据,并将其发送给对方 2.接收数据并显示 并且功能数据进行选择以上的2个功能调用 例子程序如下: import socket def send_message(udp_socket): # 输入对方的ip/port dest_ip = input("请输入对方的ip:") dest_port = int(input("请输入对象的port:")) # 读

python—多任务版udp聊天机器人

将多任务(多线程)引入到udp聊天机器人,可以实现同时发送消息和接收消息 1 import socket 2 import threading 3 4 5 def udp_send(udp_socket,ip,port): 6 while True: 7 try: 8 # 获取发送的信息 9 data = input('请输入要发送的信息:') 10 udp_socket.sendto(data.encode('gbk'), (ip,port)) 11 12 except Exception a