python基于udp实现多人聊天和私人聊天(兼容windows/linux)

说明

服务器端
  • 用户注册信息存储在数据库user_informance中,创建的字段和表在源代码注释中

  • 用户登录后,会将用户及其ip_addr和端口号记录在数据库address_informance中,数据类型详见注释

  • 首次运行前记得在目录下使用sqlite3创建上面提到的俩个数据库

客户端
  • 每次运行客户端端口是随机的,所以登录后,退出一定要输入exit,让服务器端删除登录地址信息,避免不必要的麻烦
  • 公聊只需要在对话框中输入就好了
  • 私聊某用户的方法是:在对话框中输入private+空格+对象用户名+空格+内容
  • 退出输入: exit

特别注意

  • 只在windows下运行,没来及在linux中,linux自测可行性
  • 若需要将客户端和服务器端放在不同主机(ip)上请修改客服端的发送ip地址参数,以及检查list_name,list_port这几个根据他值索引问题,同时得连接远程数据库,sqlite3此时不能满足条件
  • 本人菜鸡,没有使用class类(感觉功能不够怎么强大,关键是我不会用啊哈哈哈)有问题欢迎留言

1.客户端源代码:

import socket  
import multiprocessing  
import random  
def main():  
    sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)#调用套接字,数据类型为UDP  
    my_port=random.randint(1024,10000)  
    print('your port:',my_port)  
    my_address=('127.0.0.1',my_port)  
    sock.bind(my_address)  
    server_address=('127.0.0.1',8888)  
    chat(server_address,sock)  
def chat(server_addr,sock):#用户聊天功能函数,包括注册,登录,发送消息,消息接收功能  
    try:  
            num=input('登录请输入数字1,注册请输入数字2:\n')  
  
            if num=='1':  
                login(server_addr,sock)  
            elif num=='2':  
                register(server_addr,sock)  
            else:  
                print('选择出错')  
            p = multiprocessing.Process(target=recvmsg, args=(sock,))#类似于linux下的os.fork函数创建子进程  
            p.daemon = True  
            p.start()  
            sendmsg(server_addr,sock)  
  
  
    except KeyboardInterrupt:  
            sock.close()  
def sendmsg(client,sock):#发送消息函数,若需要私聊则需要使用以下格式:private+空格+user_name+空格+内容  
    while True:  
        data=input('您:\n')  
        sock.sendto(data.encode(),client)  
def recvmsg(sock):  
    while True:  
        data,addr=sock.recvfrom(1024)  
        data_text=data.decode('utf-8')  
        print(data_text)  
def register(server_addr,sock):#用户注册输入,并将信息提交给服务器,注册成功需要重启程序进行登录  
    user_name = input('请输入您的账户名\n')  # 输入聊天信息  
    user_pwd  =input('请输您的密码\n')  
    user_email=input('请输入您的邮箱\n')  
    send_data='register'+' '+user_name+' '+user_pwd+' '+user_email  
    sock.sendto(send_data.encode(), server_addr)  # 网络中以字节传输  
def login(server_addr,sock):#输入用户信息,并将信息发送给服务端  
    user_name = input('请输入您的账户名\n')  # 输入账户信息  
    user_pwd = input('请输您的密码\n')  
    send_data = 'login' + ' ' + user_name + ' ' + user_pwd  
    sock.sendto(send_data.encode(), server_addr)  
if __name__=='__main__':  
    main()  

2.服务器端

import socket
import hashlib
import sqlite3
#database_name=user_informance.db table_name=USER :username text primary key not null,password text not null,mail text
#database_name=address_informance.db  table_name=ADDR ADDR(name text primary key not null,address text not null)CREATE TABLE ADDR(name text primary key not null,address text not null,port integer not null
def register(username1,passwd,mail,sock,msg_addr):#接收用户端提交的数据进行注册
    conn=sqlite3.connect('user_informance.db')#数据放在旗下的表USER里面
    c=conn.cursor()
    check_name=c.execute('select username from USER ')
    flag=0#flag=0可正常注册
    for row in check_name:
        k = row[0]
        if username1==k:
            flag=1
            break
    if flag==1 :
        err_data='用户名已存在请关掉程序重新注册!!!'
        sock.sendto(err_data.encode(),msg_addr)
    else:
        pwd = hashlib.md5(passwd.encode())#密码以md5加密方式存储
        passwd = pwd.hexdigest()
        c.execute('INSERT INTO USER (username,password,mail) VALUES (?,?,?)',(username1,passwd,mail))#usernam text/passwd text/mail text
        
        data_text='用户注册成功,请登录进行会话'
        sock.sendto(data_text.encode(),msg_addr)

    conn.commit()
    c.close()
def login_check(username,passwd,sock,client_addr,list_addr,list_name,list_port):#服务器端将用户登录的用户名,地址,端口存进address_informance.db中,三个list分别是查询数据库得到的用户名,地址,端口
    conn = sqlite3.connect('user_informance.db')  # 数据放在旗下的表USER里面
    c = conn.cursor()
    pwd = hashlib.md5(passwd.encode())
    passwd = pwd.hexdigest()
    pd=c.execute('SELECT password FROM USER WHERE USER.username= (?)',(username,))
    pd_ckeck=pd.fetchone()

    if passwd==pd_ckeck[0]:
        login_text='登陆成功,您可以开始对话了'
        sock.sendto(login_text.encode(),client_addr)
        coonn = sqlite3.connect('address_informance.db')
        coo=coonn.cursor()
        sql_text='''INSERT OR IGNORE INTO ADDR (name,address,port) values(?,?,?)''' 
        print(username,'login',client_addr)
        coo.execute(sql_text,(username,client_addr[0],client_addr[1]))#将用户名、地址、端口存入表ADDR中
        coonn.commit()
        coonn.close()
    else:
        err_text='用户名或者密码错误请重新输入'
        sock.sendto(err_text.encode(),client_addr)
    conn.commit()
    c.close()

def doQuit(sock,name,list_addr,list_name,list_port):#用户退出,服务器将存在数据库中的登录的地址和端口信息删除
    message = '\n%s 退出了聊天室' %name
    for u in list_name:
        if u!=name:
            private_add = list_addr[list_name.index(u)]
            private_port= list_port[list_name.index(u)]
            sock.sendto(message.encode(),(private_add,private_port))
        else:
            sock.sendto('exit'.encode(),(list_addr[list_name.index(u)],list_port[list_name.index(u)]))
    ccoonn = sqlite3.connect('address_informance.db')
    ccoo = ccoonn.cursor()
    sql_text = '''DELETE FROM ADDR WHERE name=?'''
    ccoo.execute(sql_text, (name,))#删除登录地址信息
    ccoonn.commit()
    ccoonn.close()
def main():
    sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    address = (('127.0.0.1', 8888))
    sock.bind(address)
    # coon=sqlite3.connect('address_informance.db')
    # co=coon.cursor()
    # userlist = {'admin': '(127.0.0.1,8888)',}
    getserver(sock)

def getserver(sock):#服务器中转功能,包括注册,登录、接收用户会话并转发给私人或者是全部在线用户、用户退出等功能

    while True:
        coon = sqlite3.connect('address_informance.db')
        msg,client_addr=sock.recvfrom(1024)
        msglist = msg.decode().split(' ')  # 拆分数据,以空格为分隔


        co=coon.cursor()
        sql1='''select * from ADDR'''
        list_name=list()
        list_addr=list()
        list_port=list()
        k=co.execute(sql1)
        coon.commit()

        for row in k:
            list_name.append(row[0])
            list_addr.append(row[1])
            list_port.append(row[2])
        co.close()
		#三个list表,查找出所有已记录的在线用户的信息包括用户名,地址,端口
        if (client_addr[1] in list_port)==True:#收到消息的发送端是已登录的用户
            msg_user = list_name[list_port.index(client_addr[1])]
            print(msg_user + ':' + msg.decode('utf-8'))
        if  msglist[0]=='login' :
            login_check(msglist[1],msglist[2],sock,client_addr,list_addr,list_name,list_port)
        elif msglist[0]=='register' :
            print('registering')
            register(msglist[1],msglist[2],msglist[3],sock,client_addr)

        elif msglist[0]=='private' :
                private_add=list_addr[list_name.index(msglist[1])]
                private_port=list_port[list_name.index(msglist[1])]
                private_user=list_name[list_port.index(client_addr[1])]
                content=private_user+':'+''.join(msglist[2:])
                sock.sendto(content.encode(),(private_add,private_port))
        elif msglist[0]=='exit':
                private_user = list_name[list_port.index(client_addr[1])]
                userlist=doQuit(sock,private_user,list_addr,list_name,list_port)
        else:   #若是公聊,将用户的对话发送给所有在线用户
            private_user = list_name[list_port.index(client_addr[1])]
            content_all='%s:'%private_user+msg.decode()
            for usr in list_name:
                if usr != private_user:
                    private_add = list_addr[list_name.index(usr)]
                    private_port= list_port[list_name.index(usr)]
                    sock.sendto(content_all.encode(),(private_add,private_port))

if __name__ == '__main__':
    main()


可借鉴,hdu伙伴切勿整抄,不然若是同一老师则直夸类行
有帮助的话,记得点点👍哦,大佬轻喷

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值