草庐IT

如何用Python做一个聊天程序(1)(没废话,超实用!)

学霸小鼠研发团队 2023-09-05 原文

以前我用过编程猫的Coco编辑器做过一个聊天App,但感觉不是很爽,处处都要受到限制。于是我按照我在编程猫上的思路,用Python制作了一个聊天程序。

思路

  1. 下载一个MySQL数据库,并做好处理。这个数据库相当于整个程序的服务端。

  1. 客户端使用tkinter的GUI制作,主要功能包括:收信息,发信息。收发信息的数据储存在MySQL的信息收发数据库。

  1. 同时需要在MySQL里创建一个账户管理的数据库,用来储存账号信息,包括账号名,密码,昵称等等。

服务端

MySQL的配置

  1. 首先在MySQL官网下载一个MySQL(小白推荐阅读:(70条消息) MySQL安装配置教程(超级详细、保姆级)_SoloVersion的博客-CSDN博客_mysql安装配置)。推荐下载5.7版本,同时建议下载一个Navicat,管理数据的时候更加可视化。

  1. 配置完成后在MySQL上开放权限。(“%”表示任何主机均可连接你的数据库)

(提示:Windows用户该权限放开后无法连接大概率是防火墙问题,在防火墙的入站规则中将你的MySQL端口(默认3306)设为通过)。

(Linux系统大概率是MySQL文件夹的my.cnf的bind_address的值为127.0.0.1,首先将MySQL服务关闭,然后将127.0.0.1改为0.0.0.0,启动,但这样会有非常大的风险,有可能会导致数据库无法启动,不建议操作!)。

grant all privileges on *.* to root@'%' identified by '你的密码' with grant option;

flush privileges;
  1. 创建数据库。(先将数据库,表,以及行改为utf-8,否则无法插入中文)

create database 你的数据库名;

创建表

create table 账号管理(账号名 bigint, 密码 varchar(20), 昵称 varchar(20);
create table 主服务器(发送人账号 bigint, 发送人昵称 varchar(20), 发送内容 varchar(20000), 收件人账号 bigint, 已读未读 int(1));

这个时候服务器所在的局域网的所有主机都可以通过服务器所在的主机的IP地址连接上服务器,但这远远不够,我们需要全球任何一个角落的人都可以连接上这台服务器。

内网映射

这个时候我们需要下载一个叫“花生壳”的工具。

  1. 打开“花生壳”,注册账号。点击加号。

  1. 进入花生壳官网,填写数据。

应用名称

自定义,一般写个有含义的名称

应用图标

可以给对应的服务选择一个图标,方便区分

映射类型

选择TCP

外网域名

选择帐号下的壳域名作为外网访问地址

外网端口

选择动态端口

内网主机

填写服务器的局域网IP地址

内网端口

3306(若内网数据库为SqlServer则是1433)

带宽

默认根据帐号等级分配相应的带宽,也可根据实际需求额外付费购买

夜间带宽

18:00-次日8:00带宽速度提升100%,速度不低于5Mbps;带宽基数越大,夜间越快

点击“保存”即可。

完成后使用Navicat尝试连接。

这个时候天南海北的人都可以通过该IP连接数据库。

客户端

准备

  1. Python 3.x(推荐使用Pycharm)

  1. 配置好的MySQL数据库

  1. 导入库(在cmd中用pip导入)

pip install pymysql
pip install threading

GUI框架

这里使用Python自带的tkinter(作者也是初次接触,太复杂的GUI我也不会😶)

from tkinter import *

def main():
    win = Tk()
    win.title('登录')
    win.geometry('400x400')
    win.resizable(False, False)
    win.config(background='light gray')

    Label(win, text='登录', bg='light gray', font=('楷体', 32), fg='black').pack()
    Label(win, text='账号', bg='light gray', font=('微软雅黑', 15), fg='black').place(x=30, y=120)
    Label(win, text='密码', bg='light gray', font=('微软雅黑', 15), fg='black').place(x=30, y=180)
    e1 = Entry(win, width=35, relief=FLAT)
    e2 = Entry(win, width=35, show='*', relief=FLAT)
    e1.place(x=100, y=126)
    e2.place(x=100, y=186)
    def sign_in():
        # 登录验证
        pass
    def sign_up():
        # 注册账号
        root = Tk()
        root.title('注册')
        root.geometry('400x400')
        root.resizable(False, False)
        root.config(background='light gray')

        Label(root, text='注册', bg='light gray', font=('楷体', 32), fg='black').pack()
        Label(root, text='账号', bg='light gray', font=('微软雅黑', 15), fg='black').place(x=30, y=120)
        Label(root, text='密码', bg='light gray', font=('微软雅黑', 15), fg='black').place(x=30, y=180)
        Label(root, text='昵称', bg='light gray', font=('微软雅黑', 15), fg='black').place(x=30, y=240)
        e11 = Entry(root, width=35, relief=FLAT)
        e22 = Entry(root, width=35, show='*', relief=FLAT)
        e33 = Entry(root, width=35, relief=FLAT)
        e11.place(x=100, y=126)
        e22.place(x=100, y=186)
        e33.place(x=100, y=246)
        def signup():
            # 注册详情
            pass
        Button(root, text='注册', bg='green', fg='white', command=signup, width=10, height=1, relief=RIDGE).pack(side='bottom', pady=60)
    Button(win, text='点击注册', bg='light gray', fg='blue', command=sign_up, width=10, height=1, relief=FLAT).pack(side='bottom')
    Button(win, text='登录', bg='green', fg='white', command=sign_in, width=10, height=1, relief=RIDGE).pack(side='bottom', pady=90)

if __name__ == '__main__':
    main()

客户端+服务器

我们使用Python的pymysql库,它可以很方便得连接MySQL数据库。

使用详情参考:(70条消息) pymysql的使用教程_Andy86666的博客-CSDN博客_pymysql

验证账号

验证账号的具体思路是:

  1. 连接服务器。

  1. 获取输入的手机号。

  1. 与数据库中现有的手机号进行比对,比对成功下一步,不成功直接弹窗“该账号不存在!”。

  1. 获取该账号的信息,如昵称,手机号,密码等。

  1. 对比输入密码与数据库存在密码,相同则成功登录,不同就弹窗“密码错误”。

具体代码如下:

def sign_in():
        # 验证账号
        try:
            conn = pymysql.connect(host='刚刚映射的IP', port=刚刚映射的端口, user='用户名', password='你的MySQL密码', database='数据库名称')
            cursor = conn.cursor()
            try:
                sql1 = 'select * from 账号 where 手机号=' + str(e1.get())
                cursor.execute(sql1)
                global all1
                all1 = cursor.fetchone()
                conn.close()
                cursor.close()
                if all1 == None:
                    messagebox.showerror('学霸小鼠', '该账号不存在!')
                else:
                    passw = all1[2]
                    if e2.get() == passw:
                        messagebox.showinfo('学霸小鼠', '登录成功')
                        win.destroy()
                        # f2.start()(整体代码需要)
                    else:
                        messagebox.showerror('学霸小鼠', '密码错误!')
            except:
                messagebox.showerror('学霸小鼠', '请检查输入!')
        except:
            messagebox.showerror('学霸小鼠', '服务器未开放!')

注册账号

思路:

  1. 通过GUI的方式获取用户所要注册的账号,信息包括手机号,昵称,密码。

  1. 判断是否符合规则,例如:手机号是否符合MySQL的bigint(不符合就会报错),建立二次填写密码机制,防止填写错误。这里可以用try...except...语句。

  1. 判断完成后将数据上传至数据库储存,注册完毕。

代码如下:

try:
    conn = pymysql.connect(host='xx.xx.xx.xx', port=xxxxx, user='xxxx', password='xxxxx',database='xxxxx')
                cursor = conn.cursor()
                cursor1 = conn.cursor()
                try:
                    sql2 = "select * from 账号 where 手机号=" + str(e11.get())
                    cursor.execute(sql2)
                    all2 = cursor.fetchone()
                    if all2 == None and e22.get() == e44.get():
                        sql3 = "insert into 账号 values('" + str(e33.get()) + "', " + str(e11.get()) + " ,'" + str(e22.get()) + "');"
                        # print(sql3)
                        cursor1.execute(sql3)
                        conn.commit()
                        messagebox.showinfo('学霸小鼠', '注册成功!')
                        cursor1.close()
                        cursor.close()
                        conn.close()
                        root.destroy()

                    else:
                        messagebox.showwarning('学霸小鼠', '错误!(该账号已注册或您两次输入的密码不一致!)')
                except:
                    messagebox.showerror('学霸小鼠', '请检查输入!')
            except:
                messagebox.showerror('学霸小鼠', '服务器未开放!')

运行

发送界面

大致框架

  1. 左边做一个Text收件箱,右边做一个Text发件箱。(左边只读,右边可改)

  1. 三个按钮:刷新、发送、清空聊天记录。

  1. 两个滑动块,一左一右。

发送端

思路:

  1. 获取GUI界面的输入信息,对比收件人账号与服务器账号,有此账号继续,无此账号禁止发送(防止垃圾信息过多,导致服务器臃肿)。

  1. 尝试将信息传输至服务器,成功则完成,不成功报错。传输内容如下:(我定义的已读未读中,0代表未读,1代表已读,发送时自动将信息标记为0)

def send():
        try:
            conn = pymysql.connect(host='xx.xx.xx.xx', port=xxxx, user='xxxx', password='xxxx', database='xxx')
            cursor = conn.cursor()
            sql5 = 'select * from 账号 where 手机号={}'.format(e4.get())
            cursor.execute(sql5)
            all2 = cursor.fetchone()
            if all2 == None:
                messagebox.showerror('学霸小鼠', '没有此收件人,请检查!')
            else:
                try:
                    sql4 = "insert into 内容 values('{}', '{}', {}, {}, '{}', {})".format(e3.get('1.0', 'end'), all1[0], all1[1], e4.get(), time.ctime(), 0)
                    cursor.execute(sql4)
                    conn.commit()
                    cursor.close()
                    conn.close()
                    messagebox.showinfo('学霸小鼠', '发送成功!')
                except:
                    messagebox.showerror('学霸小鼠', '发送失败!请检查信息!')
        except:
            messagebox.showerror('学霸小鼠', '未知错误!请联系管理员解决!')

接收端

思路:

  1. 实时比对当前手机号是否存在与发送数据库的“收件人账号”中,存在则输出。

  1. 输出的内容是一组元组,需要进行简单处理。

  1. 处理完毕后提取相关信息,插入到收件箱上。

  1. 将已读未读标记为1,防止下一轮循环中再次插入。

def receive():
        try:
            e5.configure(state='normal')
            e5.delete('1.0', END)
            # we = '{}的收信箱:\n\n'.format(all1[0])
            # e5.insert(INSERT, we)
            conn = pymysql.connect(host='', port=49657, user='root', password='zhang2008', database='mindchat')
            cursor = conn.cursor()
            sql6 = 'select * from 内容 where 收件人账号={}'.format(all1[1])
            cursor.execute(sql6)
            all8 = cursor.fetchall()
            for t in all8:
                e5.insert('end', '{}\n{}({})发送的内容\n{}\n\n\n'.format(t[4], t[1], t[2], t[0]))
            sql11 = 'update 内容 set 已读未读=1 where 收件人账号={}'.format(all1[1])
            cursor.execute(sql11)
            conn.commit()
            e5.configure(state='disabled')
            conn.close()
            cursor.close()

        except:
            messagebox.showerror('学霸小鼠', '未知错误!请检查数据或联系管理员!')

这可以与刷新按钮绑定,但无法实时刷新。

实时通讯

思路

  1. 写一个while循环,重复捕捉(同上),间隙为5秒(否则GUI会闪动十分严重)

  1. 插入。

def main3():
    try:
        while True:
            e5.configure(state='normal')
            # e5.delete('1.0', END)
            conn = pymysql.connect(host='xxx', port=xx, user='xx', password='xxxx', database='xxxx')
            cursor = conn.cursor()
            sql6 = 'select * from 内容 where 收件人账号={} and 已读未读=0'.format(all1[1])
            cursor.execute(sql6)
            all2 = cursor.fetchall()
            # print(all2)
            for t in all2:
                e5.insert('end', '{}\n{}({})发送的内容\n{}\n\n\n'.format(t[4], t[1], t[2], t[0]))
            sql11 = 'update 内容 set 已读未读=1 where 收件人账号={}'.format(all1[1])
            cursor.execute(sql11)
            conn.commit()
            e5.configure(state='disabled')
            time.sleep(5)
            conn.close()
            cursor.close()
            zh.update()



    except:
        pass

清理聊天记录

思路:

  1. 新建一个按钮,与接下来的程序绑定。

  1. 当点击按钮时,删除数据库中“收件人”=当前手机号的信息。

  1. 刷新即可。

def clear():
        try:
            conn = pymysql.connect(host='xx', port=xx, user='xxx', password='xxxxx', database='xxxxx')
            cursor = conn.cursor()
            sql9 = 'delete from 内容 where 收件人账号 = {}'.format(all1[1])
            cursor.execute(sql9)
            conn.commit()
            messagebox.showinfo('学霸小鼠', '已清空您的聊天数据!')
            cursor.close()
            conn.close()
        except:
            messagebox.showerror('学霸小鼠', '服务器未开放!')

总结

我们利用Python+MySQL开发了一款实时聊天工具,喜欢的话可以加一下关注,以后我会继续发文更新,对程序进行进一步的完善。如果有什么建议可以在评论区输入你的想法。

再见!

有关如何用Python做一个聊天程序(1)(没废话,超实用!)的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  4. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  6. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  7. ruby - 在 Ruby 中编写命令行实用程序 - 2

    我想用ruby​​编写一个小的命令行实用程序并将其作为gem分发。我知道安装后,Guard、Sass和Thor等某些gem可以从命令行自行运行。为了让gem像二进制文件一样可用,我需要在我的gemspec中指定什么。 最佳答案 Gem::Specification.newdo|s|...s.executable='name_of_executable'...endhttp://docs.rubygems.org/read/chapter/20 关于ruby-在Ruby中编写命令行实用程序

  8. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  9. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  10. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

随机推荐