美文网首页
一起来做一个基于python的tcp聊天室吧

一起来做一个基于python的tcp聊天室吧

作者: 月下十一郎 | 来源:发表于2019-02-24 22:39 被阅读0次

    基于python的tcp聊天室的实现

    1.目标和思路

    2.客户端代码

    3.服务器代码

    4.运行结果

    1.目标和思路

    1.功能和目标: 类似群聊天

        [1]有人进入聊天室需要输入姓名,姓名不能重复

        [2] 有人进入聊天室时,其他人会收到通知:

            *** 进入聊天室

        [3] 一个人发消息,其他人会收到:

            ××× :××××××××

        [4] 有人退出聊天室,则其他人会收到通知:

            ××× 退出聊天室

    2.确定技术模型

        [1] 使用字典保存用户信息 {姓名:客户端套接字}

        [2] 套接字选择: tcp套接字

        [3] 转换模型 : 客户端-->>服务端-->>所有客户端

        [4] 收发关系处理: 一个客户端发送消息给服务端,服务端再转发给其他客户端

                        客户端使用多进程来分别处理收发消息

                        服务端使用多线程来管理客户端

    3.具体实现流程

        [1] 搭建网络连接

        [2] 实现登录

                客户端: × 输入姓名

                        × 将姓名发送给服务端

                        × 接收服务端反馈

                        × 如果不允许进入则重新输入,允许则进入聊天室

                        × 创建新的进程用于收发消息

                服务端:  * 创建新的线程用于管理客户端的连接

                        × 接收姓名

                        ×  判断姓名是否存在

                        ×  将结果反馈给客户端

                        × 不允许 登录结束,允许登录则将用户信息插入数据机构保存

                        × 将登录信息通知其他人

        [3] 聊天

                客户端: × 循环发送消息

                                    × 循环接收消息

                服务器: × 接收消息,判断请求类型

                        × 将消息转发给其他用户

        [4] 退出

                客户端: ×输入quit进行退出

                        × 发送进程关闭,接收进程关闭

                服务器: × 退出信息发送给其他人

                        × 将其信息从服务器清除

    2.客户端代码

    import os,sys,signal

    from socket import *

    server_addr = (('127.0.0.1',9696))

    def msg_recv(sockfd):      ##接收消息

        while True:

            data = sockfd.recv(1024)

            if data.decode() == 'q':

                break

            print(data.decode())

    def msg_send(sockfd,name):      ##发送消息

        while True:

            try:

                data = input("发言>>")

            except KeyboardInterrupt:

                data = 'quit'

            if data == 'quit':  ##退出

                msg = 'Q %s'%name

                sockfd.send(msg.encode())

                break

            else:

                msg = 'C %s %s'%(data,name)

                sockfd.send(msg.encode())

    def main():

        sockfd = socket()##创建套接字

        try:

            sockfd.connect(server_addr)

        except Exception:

            print("连接失败")

            sockfd.close()

            return

        while True:            ####输入姓名登录

            name = input("请输入昵称:")

            sockfd.send(('L '+name).encode())  ## L 区分消息类型

            data = sockfd.recv(128)

            if data.decode() == 'OK':

                print("你已经进入9696聊天室")

                break

            else:

                print(data.decode())

        signal.signal(signal.SIGCHLD,signal.SIG_IGN)

        pid = os.fork()

        if pid < 0:

            sys.exit("err") 

        elif pid == 0:        ##子进程

            msg_recv(sockfd)

        else:

            msg_send(sockfd,name)

        sys.exit("退出")

    if __name__ == "__main__":

        main()

    3.服务器代码

    from threading import Thread

    from socket import *

    import os,sys

    Host = '0.0.0.0'

    Post = 9696

    address = (Host,Post)

    chat_name = {}  ## name:conn

    jobs = {}  ###conn:t  存储线程对象t   

    #conn_stat = {}  ###  conn:'true'  存储套接字的状态 true为运行  false 为结束线程

    def do_login(conn,name):        ##登录

        if name not in chat_name:

            conn.send(b'OK')

        else:

            conn.send("昵称已经存在".encode())

            return

        msg = "%s 进入9696聊天室" %name

        for c in chat_name:

            chat_name[c].send(msg.encode())

        chat_name[name] = conn

    def do_chat(conn,msg,name):

        text = "%s :%s"%(name,msg)

        for n in chat_name:

            if n != name:

                chat_name[n].send(text.encode())

    def do_quit(conn,name):

        msg = "%s 退出9696聊天室了"%name

        for c in chat_name:

            if c == name:

                conn.send(b'q')

            else:

                chat_name[c].send(msg.encode())

        del chat_name[name]

        #conn_stat[conn] = 'false'

        conn.close()

    def do_request(conn):  ##用来处理客户端的请求

        while True:

            data = conn.recv(1024).decode().strip().split(' ')

            if data[0] == 'L':  ##登录

                name = data[-1]

                do_login(conn,name)

            elif data[0] == 'C':    ##聊天

                name = data[-1]

                msg = ''.join(data[1:-1])

                do_chat(conn,msg,name)

            elif data[0] == 'Q':  ##退出

                name = data[-1]

                do_quit(conn,name)

                break

    def main():

        sockfd = socket()  ##tcp套接字

        sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)    ##端口重用

        sockfd.bind(address)

        sockfd.listen(5)

        while True:

            try:

                conn,addr = sockfd.accept()

            except KeyboardInterrupt:

                sockfd.close()

                sys.exit("退出")

            except Exception as e:

                print(e)

                continue

            print("Connect from:",addr)

            t = Thread(target=do_request,args=(conn,))

            t.start()

            jobs[conn] = t

            #conn_stat[conn] = 'true'

            ###回收线程  当有线程结束,只有当新的客户端连接进来才会回收结束的线程

            for c in jobs:

                if c._closed is True:

                    jobs[c].join()

    if __name__ == '__main__':

        main()

    4.运行结果

    1.运行客户端和服务器

    2.输入姓名

    3.发送消息

    4.退出客户端

    运行中收到的消息会显示在“发言>>”之后,可以在其后加上“\r”让光标回到行首,效果会好一点。。。。。

    相关文章

      网友评论

          本文标题:一起来做一个基于python的tcp聊天室吧

          本文链接:https://www.haomeiwen.com/subject/nwdiyqtx.html