欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

python简单实现聊天室功能(代码教程)

程序员文章站 2022-04-24 18:21:01
聊天室程序需求: 我们要实现的是简单的聊天室的例子,就是允许多个人同时一起聊天,每个人发送的消息所有人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天。如...

聊天室程序需求:

我们要实现的是简单的聊天室的例子,就是允许多个人同时一起聊天,每个人发送的消息所有人都能接收到,类似于 QQ 群的功能,而不是点对点的 QQ 好友之间的聊天。如下图:

python简单实现聊天室功能(代码教程)

这里我们首先要知道《python网络编程》知识,其中要明白什么是Socket以及如何使用Socket 实现不同主机间的通信。

OK,我这里直接上TCP版本的server.py和client.py文件

运行时分别运行server.py和client.py文件即可,或者在编译器上直接运行,效果图在文章末尾。

server.py

# -*- encoding:utf-8 -*-
# socket.getaddrinfo(host,  port, family=0, socktype=0, proto=0, flags=0)
# 根据给定的参数host/port,相应的转换成一个包含用于创建socket对象的五元组,
# 参数host为域名,以字符串形式给出代表一个IPV4/IPV6地址或者None.
# 参数port如果字符串形式就代表一个服务名,比如“http”"ftp""email"等,或者为数字,或者为None
# 参数family为地主族,可以为AF_INET  ,AF_INET6 ,AF_UNIX.
# 参数socktype可以为SOCK_STREAM(TCP)或者SOCK_DGRAM(UDP)
# 参数proto通常为0可以直接忽略
# 参数flags为AI_*的组合,比如AI_NUMERICHOST,它会影响函数的返回值
# 附注:给参数host,port传递None时建立在C基础,通过传递NULL。
# 该函数返回一个五元组(family, socktype, proto, canonname, sockaddr),同时第五个参数sockaddr也是一个二元组(address, port)
# 更多的方法及链接请访问
# Echo server program

#socket - tcp - server.py(服务端):
from socket import *
import sys
import threading
from time import ctime
from time import localtime
import traceback
import time
import subprocess

reload(sys)
sys.setdefaultencoding("utf8")

HOST = '127.0.0.1'
PORT = 8555  # 设置侦听端口
BUFSIZ = 1024


class TcpServer():
    def __init__(self):
        self.ADDR = (HOST, PORT)
        try:
            self.sock = socket(AF_INET, SOCK_STREAM)
            print '%d is open' % PORT

            self.sock.bind(self.ADDR)
            self.sock.listen(5)
            # 设置退出条件
            self.STOP_CHAT = False

            # 所有监听的客户端
            self.clients = {}
            self.thrs = {}
            self.stops = []

        except Exception, e:
            print "%d is down" % PORT
            return False

    def IsOpen(ip, port):

        s = socket(AF_INET, SOCK_STREAM)
        try:
            s.connect((ip, int(port)))
            # s.shutdown(2)
            # 利用shutdown()函数使socket双向数据传输变为单向数据传输。shutdown()需要一个单独的参数,
            # 该参数表示s了如何关闭socket。具体为:0表示禁止将来读;1表示禁止将来写;2表示禁止将来读和写。
            print '%d is open' % port
            return True
        except:
            print '%d is down' % port
            return False

    def listen_client(self):
        while not self.STOP_CHAT:
            print(u'等待接入,侦听端口:%d' % (PORT))
            self.tcpClientSock, self.addr = self.sock.accept()
            print(u'接受连接,客户端地址:', self.addr)
            address = self.addr
            # 将建立的client socket链接放到列表self.clients中
            self.clients[address] = self.tcpClientSock
            # 分别将每个建立的链接放入进程中,接收且分发消息
            self.thrs[address] = threading.Thread(target=self.readmsg, args=[address])
            self.thrs[address].start()
            time.sleep(0.5)

    def readmsg(self, address):
        # 如果地址不存在,则返回False
        if address not in self.clients:
            return False
        # 得到发送消息的client socket
        client = self.clients[address]
        while True:
            try:
                # 获取到消息内容data
                data = client.recv(BUFSIZ)
            except:
                print error
                self.close_client(address)
                break
            if not data:
                break
            # python3使用bytes,所以要进行编码
            # s='%s发送给我的信息是:[%s] %s' %(addr[0],ctime(), data.decode('utf8'))
            # 对日期进行一下格式化
            ISOTIMEFORMAT = '%Y-%m-%d %X'
            stime = time.strftime(ISOTIMEFORMAT, localtime())
            s = u'%s发送给我的信息是:%s' % (str(address), data.decode('utf8'))
            # 将获得的消息分发给链接中的client socket
            for k in self.clients:
                self.clients[k].send(s.encode('utf8'))
                self.clients[k].sendall('sendall:' + s.encode('utf8'))
                print str(k)
            print [stime], ':', data.decode('utf8')
            # 如果输入quit(忽略大小写),则程序退出
            STOP_CHAT = (data.decode('utf8').upper() == "QUIT")
            if STOP_CHAT:
                print "quit"
                self.close_client(address)
                print "already quit"
                break

    def close_client(self, address):
        try:
            client = self.clients.pop(address)
            self.stops.append(address)
            client.close()
            for k in self.clients:
                self.clients[k].send(str(address) + u"已经离开了")
        except:
            pass
        print str(address) + u'已经退出'


if __name__ == '__main__':
    tserver = TcpServer()
    tserver.listen_client()

client.py

# -*- encoding:utf-8 -*-
from socket import *
import sys
import threading
import time
#socket - tcp - client.py (客户端):
reload(sys)
sys.setdefaultencoding("utf8")

# 测试,连接本机
HOST = '127.0.0.1'
# 设置侦听端口
PORT = 8555
BUFSIZ = 1024


class TcpClient:
    ADDR = (HOST, PORT)

    def __init__(self):
        self.HOST = HOST
        self.PORT = PORT
        self.BUFSIZ = BUFSIZ
        # 创建socket连接
        self.client = socket(AF_INET, SOCK_STREAM)
        self.client.connect(self.ADDR)
        # 起一个线程,监听接收的信息
        self.trecv = threading.Thread(target=self.recvmsg)
        self.trecv.start()

    def sendmsg(self):
        # 循环发送聊天消息,如果socket连接存在则一直循环,发送quit时关闭链接
        while self.client.connect_ex(self.ADDR):
            data = raw_input('>:')
            if not data:
                break
            self.client.send(data.encode('utf8'))
            print(u'发送信息到%s:%s' % (self.HOST, data))
            if data.upper() == "QUIT":
                self.client.close()
                print u"已关闭"
                break

    def recvmsg(self):
        # 接收消息,如果链接一直存在,则持续监听接收消息
        try:
            while self.client.connect_ex(self.ADDR):
                data = self.client.recv(self.BUFSIZ)
                print(u'从%s收到信息:%s' % (self.HOST, data.decode('utf8')))
        except Exception, e:
            print str(e)


if __name__ == '__main__':
    client = TcpClient()
    client.sendmsg()

结果展示:

我运行了两次client.py文件,表示我有两个用户进行通信,服务器会接收到两个用户发送的消息。

server.py

python简单实现聊天室功能(代码教程)

client.py

第一个用户首先与服务器连接

python简单实现聊天室功能(代码教程)

第二个用户也进来了,现在两个用户之间可以相互发送消息了

python简单实现聊天室功能(代码教程)