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

基于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. UVA1589 Xiangqi

    Xiangqi is one of the most popular two-player board games in China. The game represents a battle bet ...

  2. editor.md实现Markdown编辑器

    editor.md实现Markdown编辑器 Markdown和Editor.md简介 Markdwon编辑器在技术工作者圈子中已经越来越流行,简单的语法,统一的格式,强大的扩展功能,最重要的是:你可 ...

  3. Android原理View、ViewGroup

    Android的UI界面都是由View和ViewGroup及其派生类组合而成的.其中,View是所有UI组件的基类,而ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.Andro ...

  4. Linux下使用VirtualBox安装Windows系统

    (文档比较长,只是写的详细,实际操作起来相对简单.) 由于一些特殊原因,我们并不能完全抛下Windows而使用Linux.VirtualBox 是一款虚拟机软件,支持多系统.在Linux下安装 Vir ...

  5. LeetCode_Palindrome Partitioning II

    Given a string s, partition s such that every substring of the partition is a palindrome. Return the ...

  6. 如何向投资人展示——How to Present to Investors

    著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:茶叶末链接:http://www.zhihu.com/question/23638879/answer/34525204来源: ...

  7. 热点块引发的cache buffers cahins latch

    热点块引发的Cache buffer Chains latch: SQL语句即便适当进行了调优,有时也无法解决cache buffers cahins latch,若在编写SQL语句时的SQL工作方式 ...

  8. vijos1777 引水入城

    描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N行M列的矩形,其中每个格子都代表一座城市,每座城市都有一个海拔高度. 为了使居民们都尽可能 ...

  9. 捆绑和缩小(BundleConfig.RegisterBundles) 第五章 : MVC中的使用 | {version}用法

    使用捆绑与 ASP.NET MVC 放缩法 在这一节我们将创建 ASP.NET MVC 项目,审查捆绑和缩小.首先,创建一个新的 ASP.NET MVC 互联网项目,命名为MvcBM ,而无需更改任何 ...

  10. print带参数格式

    string_1 = "Camelot" string_2 = "place" print("float:%lf. int:%d string:%s. ...