课程设计的时候制作的多线程聊天软件程序

基于python3.4.3

import socket
import pickle
import threading
import tkinter
import os
import datetime
import time
try:
import pymysql
except:
print("can't find pymysql") tcplocalport=8101 #TCP监听端口
tcpconnectport=8101 #TCP连接端口
udplocalport=8201 #广播监听端口
udpconnectport=8201 #广播连接端口
filelocalport=8301 #文件监听接口
fileconnectport=8301 #文件连接端口
localIP=socket.gethostbyname(socket.gethostname()) #本机IP
print("localip:",localIP)
print('localtcpport:',tcplocalport) #sockdict字典用于存放本机作为客户端的连接对象
sockdict={} #filedict字典用于存放文件传输的信息
#filedict['IP']=['filename',filesize,fpobj,restsize]
filedict={}
sendfileflag={} #用于调用软件的图形界面
showdict={} #转换用表
#a为address,i为listbox的index值,n为name
a2i={}
a2n={}
i2a={} myname='a' sqlflag=0 #MYSQL启用标志,若启用MYSQL,则为1 #用于通讯的类,type为通讯指令的类型,name为发送端的名称
#data为正文,target为目标对象,time为发送时的时间
class talkdata:
def __init__(self,ttype,tname,tdata,ttarget=""):
self.dtype=ttype
self.dname=tname
self.ddata=tdata
self.dtarget=ttarget
self.dtime=gettime() #获取时间的函数
def gettime():
now = datetime.datetime.now()
return now.strftime('%Y-%m-%d %H:%M:%S') #解析接收到的数据
def solvedata(data_str,address,protocols):
global sockdict
global filedict
global a2n
global sendfileflag
data_obj=pickle.loads(data_str)
if data_obj.dtype=="searchse" and (address[0]!=localIP or data_obj.dname!=myname): #搜索发起类型
reply=talkdata("searchre",myname,"")
if sockdict.get(address[0])==None:
socketconnect(address[0],tcpconnectport)
send(sockdict[address[0]],reply)
if data_obj.dtype=="searchre" and (address[0]!=localIP or data_obj.dname!=myname): #搜索回复类型
a2n[address[0]]=data_obj.dname
"""if data_obj.dtype=="tcpcon":
if showdict.get(address[0])==None:
socketconnect(address[0],tcpconnectport)
threading.Thread(target=
createfgui_guif,arg=
(sockdict[address[0]],(address[0],tcpconnectport))).start()
"""
if data_obj.dtype=="str": #聊天内容类型
adata=data_obj.dtime+"\n"+data_obj.dname+':'+data_obj.ddata
if showdict.get(address[0])==None:
a2n[address[0]]=data_obj.dname
socketconnect(address[0],tcpconnectport)
threading.Thread(target=
createfgui_guif,args=
(sockdict[address[0]],(address[0],tcpconnectport))).start()
time.sleep(0.5)
showdict[address[0]].insert('end',adata)
print(data_obj.ddata)
if data_obj.dtype=="filehead": #发送文件头类型
filename=data_obj.ddata[0]
filesize=data_obj.ddata[1]
restsize=filesize
print("filename:",filename)
print("filesize:",filesize) filetk=tkinter.Tk()
filetk.withdraw()
fd=tkinter.filedialog.FileDialog(filetk)
filesavename=fd.go()
filetk.destroy()
if filesavename==None:
filef=talkdata('fileflag',myname,"refuse")
else:
#fp=open(filename,'wb')
#fp=open(input("filename:"),'wb')
fp=open(filesavename,'wb')
filedict[address[0]]=[filename,filesize,fp,restsize]
if sockdict.get(address[0])==None:
socketconnect(address[0],tcpconnectport)
filef=talkdata('fileflag',myname,"accept")
send(sockdict[address[0]],filef)
if data_obj.dtype=="fileflag": #文件允许接收类型
if data_obj.ddata=="accept":
sendfileflag[address[0]]=1
print("start send file")
if data_obj.ddata=="refuse":
sendfileflag[address[0]]=2
if data_obj.dtype=="udpstr" and (address[0]!=localIP or data_obj.dname!=myname): #广播聊天内容类型
adata=data_obj.dtime+"\n"+data_obj.dname+':'+data_obj.ddata
showdict[data_obj.dtarget].insert('end',adata)
if sqlflag==1 and protocols=='tcp':
sqlsavedata(data_obj,address[0]) #连接MYSQL
def sqlinit():
global sqlcon,sqlcur,sqlflag
sqlcon=pymysql.connect(host='localhost',user='root',passwd='',port=3306)
sqlcur=sqlcon.cursor()
try :
sqlcon.select_db('talk')
except :
sqlcur.execute('create database if not exists talk')
sqlcon.select_db('talk')
sqlcon.commit()
sqlflag=1
print('connect sql') #创建表
def sqlcreattable(ip):
global sqlcon,sqlcur
daip=''
for i in ip:
if i=='.':
i='_'
daip=daip+i
sqlcur.execute("""create table if not exists %s
(type varchar(20),
name varchar(20),
data varchar(500),
time datetime)""" % daip)
sqlcon.commit() #将数据加入数据库
def sqlsavedata(data_obj,ip):
global sqlcon,sqlcur
daip=''
for i in ip:
if i=='.':
i='_'
daip=daip+i
value="insert into %s values('%s','%s','%s','%s')" % (daip,data_obj.dtype,data_obj.dname,data_obj.ddata,data_obj.dtime)
#print(value)
sqlcur.execute(value)
sqlcon.commit() #读取数据库中的数据
def sqlloaddata(ip):
global sqlcon,sqlcur
daip=''
for i in ip:
if i=='.':
i='_'
daip=daip+i
sqlcur.execute('select * from %s' % daip)
a=sqlcur.fetchall()
sqlcon.commit()
return a #发送聊天
def send(socketobj,data_obj):
data_pickle=pickle.dumps(data_obj)
try :
socketobj.send(data_pickle)
except ConnectionResetError :
address=socketobj.getpeername()
socketconnect(address[0],address[1])
sockdict[address[0]].send(data_pickle) #广播聊天对象
def sendudp(data_obj):
data_str=pickle.dumps(data_obj)
addr=('<broadcast>',udpconnectport)
udps=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udps.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
udps.sendto(data_str,addr) #发送文件
def sendfile(socketobj,filename):
fp=open(filename,'rb')
filesize=os.stat(filename).st_size
fhead=talkdata("filehead",myname,(filename,filesize))
address=socketobj.getpeername()
send(socketobj,fhead)
sendfileflag[address[0]]=0
while sendfileflag[address[0]]==0:
pass
if sendfileflag[address[0]]==2:
return 0
socketfile=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
socketfile.connect((address[0],fileconnectport)) while 1:
filedata=fp.read(1024)
if not filedata:
break
socketfile.send(filedata)
print("send over") #接收TCP信息
def rec(connect,address):
while 1:
#try:
data_str=connect.recv(1024)
if not data_str:
print("leave")
break
print('Receive TCP data from',address)
solvedata(data_str,address,'tcp')
#except:
# print('Receive TCP data error\n')
# break #接收文件
def recfile(connect,address):
while 1:
#try:
filedata=connect.recv(1024)
if not filedata:
print("leave")
break
restsize=filedict[address[0]][3]
print("Receive file data from",address,"\nRestsize:",restsize)
fp=filedict[address[0]][2]
fp.write(filedata)
restsize=restsize-len(filedata)
filedict[address[0]][3]=restsize
if restsize<=0:
fp.close()
print("Receive file successful")
#except:
# print('Receive file data error\n')
# break #接收广播信息
def socketudplisten(sockobj):
while 1:
data_str,address=sockobj.recvfrom(1024)
if not data_str:
pring("no udpdata")
if sqlflag==1 :
sqlcreattable(address[0])
solvedata(data_str,address,'udp') #文件接收端口监听
def filelisten(sockobj):
threfdict={}
while 1:
connect,address=sockobj.accept()
print("File accept ",address)
threfdict[address[0]]=threading.Thread(target=recfile,args=(connect,address))
threfdict[address[0]].start() #TCP端口监听
def socketlisten(sockobj):
global sqlflag
thredict={}
while 1:
connect,address=sockobj.accept()
print("Accept ",address)
if sqlflag==1 :
sqlcreattable(address[0])
thredict[address[0]]=threading.Thread(target=rec,args=(connect,address))
thredict[address[0]].start() #连接TCP
def socketconnect(connectIP,connectport):
global sockdict
try:
sockse=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sockse.connect((connectIP,connectport))
print("connect")
sockdict[connectIP]=sockse
if sqlflag==1 :
sqlcreattable(connectIP)
except:
print("tcp connect error") #登录按钮执行的功能
def login_guif():
global myname
if entryname.get()!='':
myname=entryname.get()
listgui.title(myname)
listgui.deiconify()
logingui.withdraw() #ip连接对话框的连接按钮执行的功能
def getip_guif():
global i2a,a2i,a2n
#连接对话框
tcpcongui=tkinter.Toplevel()
framefip=tkinter.Frame(tcpcongui)
framefip.pack()
labelip=tkinter.Label(tcpcongui,text='IP地址')
labelip.pack()
entryip=tkinter.Entry(tcpcongui)
entryip.pack()
tkinter.Button(tcpcongui,text="连接",command=lambda :inputip_guif(tcpcongui,entryip)).pack() select=lbfriends.curselection()
a=()
if select==a:
connectip=""
else:
connectip=i2a[select[0]]
entryip.insert(0,connectip) #发送文件按钮执行的功能
def sendfile_guif(socketobj,tkobj):
fd=tkinter.filedialog.FileDialog(tkobj)
filename=fd.go()
threading.Thread(target=sendfile,args=(socketobj,filename)).start() #创建私聊聊天窗口
def createfgui_guif(socketobj,address):
global showdict
global a2n
if a2n.get(address[0])==None:
name=address[0]
else:
name=a2n[address[0]]
tl=tkinter.Tk()
tl.title(name)
framereceive=tkinter.Frame(tl)
framereceive.pack()
scrollbarreceive=tkinter.Scrollbar(framereceive)
scrollbarreceive.pack(fill='y',side='right')
showtext=tkinter.Text(framereceive,height=20,
width=60,yscrollcommand=scrollbarreceive.set)
showtext.pack(side='left') framesend=tkinter.Frame(tl)
framesend.pack()
scrollbarsend=tkinter.Scrollbar(framesend)
scrollbarsend.pack(fill='y',side='right')
sendtext=tkinter.Text(framesend,height=4,
width=60,yscrollcommand=scrollbarsend.set)
sendtext.pack(side='left') framebutton=tkinter.Frame(tl)
framebutton.pack()
tkinter.Button(framebutton,text='发送信息',command=lambda:send_guif(socketobj,showtext,sendtext)).pack(side='right')
tkinter.Button(framebutton,text='发送文件',command=lambda:sendfile_guif(socketobj,tl)).pack(side='left')
tkinter.Button(framebutton,text='聊天记录',command=lambda:loaddata_guif(address[0])).pack(side='left') showdict[address[0]]=showtext
tl.mainloop() #创建广播聊天窗口
def createggui_guif(target):
global showdict
tl=tkinter.Tk()
tl.title(target)
framereceive=tkinter.Frame(tl)
framereceive.pack()
scrollbarreceive=tkinter.Scrollbar(framereceive)
scrollbarreceive.pack(fill='y',side='right')
showtext=tkinter.Text(framereceive,height=20,
width=60,yscrollcommand=scrollbarreceive.set)
showtext.pack(side='left') framesend=tkinter.Frame(tl)
framesend.pack()
scrollbarsend=tkinter.Scrollbar(framesend)
scrollbarsend.pack(fill='y',side='right')
sendtext=tkinter.Text(framesend,height=4,
width=60,yscrollcommand=scrollbarsend.set)
sendtext.pack(side='left') framebutton=tkinter.Frame(tl)
framebutton.pack()
tkinter.Button(framebutton,text='发送信息',command=lambda:sendudp_guif(target,showtext,sendtext)).pack(side='right') showdict[target]=showtext
tl.mainloop() #聊天记录按钮执行的功能
def loaddata_guif(ip):
sqldata=sqlloaddata(ip)
datagui=tkinter.Tk()
scrollbarreceive=tkinter.Scrollbar(datagui)
scrollbarreceive.pack(fill='y',side='right')
showtext=tkinter.Text(datagui,height=20,
width=60,yscrollcommand=scrollbarreceive.set)
showtext.pack(side='left')
for tadata in sqldata:
adata="%s %s \n%s:%s" % (tadata[3],tadata[0],tadata[1],tadata[2])
showtext.insert('end',adata) #私聊窗口中发送信息按钮执行的功能
def send_guif(socketobj,showtext,sendtext):
data=sendtext.get('0.0','end')
adata=gettime()+'\n'+myname+':'+data
sendtext.delete('0.0','end')
showtext.insert('end',adata)
data_obj=talkdata("str",myname,data)
if sqlflag==1:
address=socketobj.getpeername()
sqlsavedata(data_obj,address[0])
send(socketobj,data_obj) #群聊窗口中发送信息按钮执行的功能
def sendudp_guif(target,showtext,sendtext):
data=sendtext.get('0.0','end')
adata=gettime()+'\n'+myname+':'+data
sendtext.delete('0.0','end')
showtext.insert('end',adata)
data_obj=talkdata("udpstr",myname,data,target)
sendudp(data_obj) #IP对话框中连接按钮执行的功能
def inputip_guif(gui,entryip):
global sockdict
gui.withdraw()
connectip=entryip.get()
if connectip=="":
connectip="127.0.0.1"
socketconnect(connectip,tcpconnectport)
threading.Thread(target=
createfgui_guif,args=
(sockdict[connectip],(connectip,tcpconnectport))).start() #我的群组中连接按钮执行的功能,暂未加入
def getgroup_guif():
target=lbgroups.selection_get()
threading.Thread(target=
createggui_guif,args=(target,)).start() #我的好友中刷新按钮执行的功能
def refreshf_guif():
global a2n
global a2i
global i2a
a2n.clear()
a2i.clear()
i2a.clear()
lbfriends.delete(0,'end')
data=talkdata("searchse",myname,(localIP,tcplocalport))
sendudp(data)
time.sleep(1)
i=0
for key in a2n:
lbfriends.insert(i,a2n[key])
a2i[key]=i
i2a[i]=key
i=i+1 #我的群组中刷新按钮执行的功能
def refreshg_guif():
pass #登录界面
logingui=tkinter.Tk()
logingui.title('登录') framelogin=tkinter.Frame(logingui)
framelogin.pack()
labelname=tkinter.Label(framelogin,text='名称')
labelname.pack(side='left')
entryname=tkinter.Entry(framelogin)
entryname.pack(side='right') frameloginbutton=tkinter.Frame(logingui)
frameloginbutton.pack()
tkinter.Button(frameloginbutton,text=" 登录 ",command=login_guif).pack(side='right')
tkinter.Button(frameloginbutton,text="MYSQL",command=sqlinit).pack(side='left') #列表界面
#listgui=tkinter.Toplevel()
listgui=tkinter.Tk()
listgui.withdraw() framelistfriends=tkinter.Frame(listgui)
framelistfriends.pack(side='left')
lablefriends=tkinter.Label(framelistfriends,text='我的好友')
lablefriends.pack(side='top')
lbfriends=tkinter.Listbox(framelistfriends)
lbfriends.pack(side='top')
framlistfbutton=tkinter.Frame(framelistfriends)
framlistfbutton.pack()
tkinter.Button(framlistfbutton,text="刷新",command=refreshf_guif).pack(side='left')
tkinter.Button(framlistfbutton,text="连接",command=getip_guif).pack(side='right') framelistgroups=tkinter.Frame(listgui)
framelistgroups.pack(side='right')
lablegroups=tkinter.Label(framelistgroups,text='我的群组')
lablegroups.pack(side='top')
lbgroups=tkinter.Listbox(framelistgroups)
lbgroups.pack(side='top')
lbgroups.insert(0,"广播")
framlistgbutton=tkinter.Frame(framelistgroups)
framlistgbutton.pack()
tkinter.Button(framlistgbutton,text="刷新",command=refreshg_guif).pack(side='left')
tkinter.Button(framlistgbutton,text="连接",command=getgroup_guif).pack(side='right') #TCP套接字初始化
sockre=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sockre.bind(('',tcplocalport))
sockre.listen(30)
print('TCP listen') #接收文件初始化
sockref=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sockref.bind(('',filelocalport))
sockref.listen(30) #UDP套接字初始化
sockreudp=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sockreudp.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
sockreudp.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
sockreudp.bind(('',udplocalport)) #创建线程监听端口
thredlisten=threading.Thread(target=socketlisten,args=(sockre,))
thredlisten.start() threfilelisten=threading.Thread(target=filelisten,args=(sockref,))
threfilelisten.start() threudplisten=threading.Thread(target=socketudplisten,args=(sockreudp,))
threudplisten.start()

【Python网络编程】多线程聊天软件程序的更多相关文章

  1. 基于JAVA网络编程的聊天小程序

    package com.neusoft.edu.socket; import java.io.BufferedReader; import java.io.IOException; import ja ...

  2. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程 并行与并发 同步与异步 阻塞与非阻塞 CPU密集型与IO密集型 线程与进程 进 ...

  3. Python 网络编程(二)

    Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...

  4. python 网络编程 IO多路复用之epoll

    python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解     此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...

  5. python 网络编程 TCP/IP socket UDP

    TCP/IP简介 虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Micro ...

  6. python并发编程&多线程(一)

    本篇理论居多,实际操作见:  python并发编程&多线程(二) 一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一 ...

  7. 28、Python网络编程

    一.基于TCP协议的socket套接字编程 1.套接字工作流程 先从服务器端说起.服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客 ...

  8. python 网络编程:socket

    在学习socket之前,我们先复习下相关的网络知识. OSI七层模型:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层.OSI七层模型是由国际标准化组织ISO定义的网络的基本结构,不仅包括一 ...

  9. 图解Python网络编程

    返回目录 本篇索引 (1)基本原理 (2)socket模块 (3)select模块 (4)asyncore模块 (5)asynchat模块 (6)socketserver模块 (1)基本原理 本篇指的 ...

随机推荐

  1. Android设置选项开发及自定义Preference样式

    一个完整的Android应用程序都应该提供选项(或者叫偏好设置等等)让用户对APP的表现形式能够进行设置,比如说是否加入用户体验计划,或者是否自动升级.定时提醒.开启自启动.后台运行等等.提供一个好的 ...

  2. 使用grid++report打印选中行

    接上一篇<hibernate+spring+mvc+Easyui框架模式下使用grid++report的总结>对grid++report做进一步开发 先写一下实现流程: 1.默认为全部载入 ...

  3. IPTABLES封闭和开放端口

    这个是个细心活儿,如果只开放特定端口,则在每一条规则里都要加上相应的端口. 任何一条不配DPORT,都有可能放行了其它端口. -A INPUT -p tcp -m tcp --dport 80 -m ...

  4. 在Visual Studio Express 2013中开发自定义控件

    在专业版本中,新建项目时有"Windows Control Library"这样一个类型可以用于新建自定义控件项目. 但是Express版本中,没有这样一个类型可供选择.这里有另外 ...

  5. HHKB Professional 2

    今天买了一副号称程序员专用的静电容键盘 HHBK Pro2无刻版,简单上手了一下,确实名不虚传,打起字来酣畅淋漓,毫不拖泥带水,感觉自己的技术提高了不少呢!!!! 由于是无刻版,需要一些时间来适应,尤 ...

  6. 迭代 Iterate

    迭代:指按照某种顺序逐个访问列表中的每一项.比如:for语句 逐个访问: lst = ['q', 'i', 'w', 's', 'i', 'r'] for i in lst: print (i), # ...

  7. Mysql日期函数,时间函数使用的总结

    一.MySQL 获得当前日期时间 函数 1.1 获得当前日期+时间(date + time)函数:now() mysql> select now();+--------------------- ...

  8. 0..n去掉一个数,给你剩下的数,找出去掉的那个数

    转载请注明转自blog.csdn.net/souldak , 微博@evagle 首先,考虑没有去掉那些数,如果n是奇数,n+1个最低位肯定是0101...01,count(0)=count(1),如 ...

  9. Dalvik虚拟机简要介绍和学习计划

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8852432 我们知道,Android应用程序是 ...

  10. border-radius讲解1

    如今CSS3中的border-radius出现后,让我们没有那么多的烦恼了,首先制作圆角图片的时间是省了,而且其还有多个优点:其一减少网站的维护的工作量,少了对图片的更新制作,代码的替换等等;其二.提 ...