python如何使用多线程_通过编写聊天程序来熟悉python中多线程及socket的用法-程序员宅基地

技术标签: python如何使用多线程  

1、引言

Python中提供了丰富的开源库,方便开发者快速就搭建好自己所需要的应用程序。本文通过编写基于tcp/ip协议的通信程序来熟悉python中socket以及多线程的使用。

2、python中的多线程以及socket的使用

在编写聊天程序程序之前,我们先熟悉一下python中多线程以及socket的使用方法。

2.1、多线程使用方法

在python中提供了Thread这个类来实现多线程程序的开发。

Thread类的原型如下:

class Thread(group=None, target=None, name=None, args=(), kwargs={})

构造函数能带有关键字参数被调用。这些参数是:

group 应当为 None,为将来实现Python Thread类的扩展而保留。

target 是被 run()方法调用的回调对象. 默认应为None, 意味着没有对象被调用。

name 为线程名字。默认,形式为'Thread-N'的唯一的名字被创建,其中N 是比较小的十进制数。

args是目标调用参数的tuple,默认为()。

kwargs是目标调用的参数的关键字dictionary,默认为{}。

而Thread类还提供了很多方法,而本文只讲述程序中所需要的1个方法,其他的方法读者可以根据需要去查阅python的官方帮助文档。

start():开启一个线程

下面将通过一段简单的程序来实验Thread的使用。

程序如下:

import threading

def print_work(cunt):for i inrange(cunt):

print'new thread print:',i

def main():

t=threading.Thread(target=print_work,args=(10,))

t.start();

sum=0;for i in range(100):

sum=sum+i

print'sum=%s' %sumif __name__=="__main__":

main()

程序比较简单,就不多做解释,不过有2点需要值得注意。

注意:

1、在使用Thread类的时候需要import threading

2、当多线程启动的方法的参数只有一个参数的时候,实例化Thread的args的参数要表示为(param1,)需要在参数后面打一个逗号,这是因为tuple元组只有一个元素的时候需要在后面加一个逗号,防止歧义。

2.2、socket的使用方法

下面介绍python中socket的使用方法。

注意:

1在python中使用socket时要import socket

2在使用socket中又服务器端和客户端之分

服务器:

1、建立一个基于tcp协议的socket类

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

其中AF_INET指定的ipv4的协议,也可以使用AF_INET6指定ipv6的协议,而STREAM是指定面向流的tcp协议。

2、s.bind(‘', 8089))

绑定一个端口号,其中'127.0.0.1'是客户端的ip地址,可以使用’0.0.0.0’来绑定网络中所有的ip,8089是指定的端口,其中端口在小于1024的时候需要有管理员的权限才能绑定。

3、s.listen(5)

开始实行监听参数:代表连接的最大数量

4、sock, addr = s.accept()

接受一个客户端的连接,返回的是一个与客户端保持连接的socket对象以及客户端的ip地址和端口。该方法也会阻塞线程,直到获得客户端的连接。

客户端:

1、s.connect(('127.0.0.1', 80))

连接到服务器,其中'www.baidu.com’也可以是服务器的ip地址。

2、s.send('hello')

发送数据’hello’。TCP连接创建的是双向通道,双方都可以同时给对方发数据。但是谁先发谁后发,怎么协调,要根据具体的协议来决定。

3、s. recv(1024)

接受连接的对方发来的数据。该方法会阻塞当前线程,所以需要一个专门的线程来接受数据。

注意:

同一个端口,被一个Socket绑定了以后,就不能被别的Socket绑定了。

3、基于python的聊天程序的流程设计

在第二点讲述了聊天程序需要用到的知识点,以及需要注意的地方,现在我们就开始来设计程序的流程吧。

把程序分为即服务器与客户端两个部分。

服务器端的流程如下图:

531939-20151023183320583-1481260743.jpg

其中user对象代表一个客户端的连接。

类结构如下图所示:

531939-20151023183328708-733466074.jpg

客户端的流程设计如下图:

531939-20151023183340583-245173896.jpg

4、聊天程序的编码过程

该程序实现的是一个相对比较简单的聊天程序,由于是基于控制台实现的,所只设计容许两个人聊天,另外消息的编码的分割符为|。

4.1、服务器端

首先建立一个User的数据结构,代码如下:

import socketclassUser:

def __init__(self,skt,username='none'):

self.skt=skt

self.username=username

def send_msg(self,msg):

self.skt.send(msg)

def logout(self):

self.skt.close()

服务端的编码如下:

import sys

import socket

import threading,time

import User

#globalvariable

userlist=[]

def hand_user_con(usr):try:

isNormar=TruewhileisNormar:

data=usr.skt.recv(1024)

time.sleep(1)

msg=data.split('|')#分析消息if msg[0]=='login':

print'user [%s] login' % msg[1]

usr.username=msg[1]

notice_other_usr(usr)if msg[0]=='talk':

print'user[%s]to[%s]:%s' % (usr.username,msg[1],msg[2])

send_msg(msg[1],msg[2])#发送消息给目标用户,参数1:目标用户,参数2:消息内容if msg[0]=='exit':

print'user [%s] exit' % msg[0]

isNormar=False

usr.close()

userlist.remove(usr)

except:

isNormar=False

#通知其他用户以上的好友

def notice_other_usr(usr):if(len(userlist)>1):

print'The two users'userlist[0].skt.send(("login|%s" % userlist[1].username))

userlist[1].skt.send(("login|%s" % userlist[0].username))else:

print'The one users'def send_msg(username,msg):for usr inuserlist:if(usr.username==username):

usr.skt.send(msg)

#程序入口

def main():

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.bind(('0.0.0.0',9999))

s.listen(5)

print u'waiting for connection...'

whileTrue:

sock,addr=s.accept()#等待用户连接

user=User.User(sock)

userlist.append(user)

t=threading.Thread(target=hand_user_con,args=(user,));

t.start()

s.close()if(__name__=="__main__"):

main()

4.2、客户端

客户端的编码如下:

import sys

import socket

import threading,time

#globalvariable

isNormar=True

other_usr=''def recieve_msg(username,s):globalisNormar,other_usr

print'Please waiting other user login...'s.send('login|%s' %username)while(isNormar):

data= s.recv(1024)#阻塞线程,接受消息

msg=data.split('|')if msg[0]=='login':

print u'%s user has already logged in, start to chat' % msg[1]

other_usr=msg[1]else:

print msg[0]

#程序入口

def main():globalisNormar,other_usrtry:

print'Please input your name:'usrname=raw_input()

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect(("127.0.0.1",9999))

t=threading.Thread(target=recieve_msg,args=(usrname,s))

t.start()

except:

print'connection exception'isNormar=Falsefinally:

passwhileisNormar:

msg=raw_input()#接受用户输入if msg=="exit":

isNormar=Falseelse:if(other_usr!=''):

s.send("talk|%s|%s" %(other_usr,msg))#编码消息并发送

s.close()if __name__=="__main__":

main()

其效果截图如下:

531939-20151023184818505-1271375305.jpg

5、结论

通过编写该聊天的程序,了解了python中多线程以及socket的使用。该聊天的程序过于简单,仅仅只是实现了这客户端-服务端-客户端信息交互的一个流程,并不是很完善,在很多地方还存在很多异常。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_39984201/article/details/110146038

智能推荐

Aubo机械臂初学(愁)——1、gazebo和Rviz联合仿真_aubo机械臂仿真-程序员宅基地

文章浏览阅读1.7k次,点赞5次,收藏33次。auboi5机械臂初学者遇到的各种问题合集_aubo机械臂仿真

POJ_1064_Cable master【二分】_poj - 1064 二分枚举答案 floor向下取整函数 原创-程序员宅基地

文章浏览阅读1.7k次。/*Cable masterTime Limit: 1000MS Memory Limit: 10000KTotal Submissions: 43878 Accepted: 9409DescriptionInhabitants of the Wonderland have decided to hold a regional programmi_poj - 1064 二分枚举答案 floor向下取整函数 原创

【前端学习】HTML学习笔记-table_table前端心得-程序员宅基地

文章浏览阅读88次。<table><colgroup><col bgcolor='red' width=200></colgroup><thead><tr><th></th></tr><tbody><tr><td></td></t..._table前端心得

CSS 之 line-height 实现单行文字垂直居中的原理_css height=line-height 可以垂直居中-程序员宅基地

文章浏览阅读1.5k次,点赞3次,收藏12次。基础知识line-height 与 font-size 的计算值之差(在 CSS 中成为“行间距”)分为两半,分别加到一个文本行内容的顶部和底部。我们暂且称之为顶部距离和底部距离,就是上图中的蓝色区域。也就是说: line-height = 顶部距离 + 内容高度(顶线和底线之间的距离) + 底部距离;顶部距离 = 底部距离;示例一: 当line-height 等于 height 时,文字垂直居中文本默认大小16px。结果:文字垂直居中。顶部距离 = 底部距离 = (line-heig_css height=line-height 可以垂直居中

uniapp实战——实现详情其他部分的结构_uniapp 实现关系图谱-程序员宅基地

文章浏览阅读241次。QQ 1274510382Wechat JNZ_aming商业联盟 QQ群538250800技术搞事 QQ群599020441解决方案 QQ群152889761加入我们 QQ群649347320共享学习 QQ群674240731纪年科技aming网络安全 ,深度学习,嵌入式,机器强化,生物智能,生命科学。叮叮叮:产品已上线 —>关注 官方认证-微信公众号——济南纪年信息科技有限公司民生项目:商城加盟/娱乐交友/创业商圈/外包兼职开发-项目发布/安全项目:态.._uniapp 实现关系图谱

如何查看其他人的ABAP authorization check log_查看authorization-程序员宅基地

文章浏览阅读375次。Created by Jerry Wang on Jul 29, 2014 Go to start of metadata在做middleware相关的scenario操作时,有时候需要evaluate其他user的authorization check log,例如在CRM tcode SMW01里发现BDoc state为validation error,点击show error butto..._查看authorization

随便推点

I.MX6 eMMC分区挂载-程序员宅基地

文章浏览阅读244次。/********************************************************************* * I.MX6 eMMC分区挂载 * 说明: * 如果想要修改分区的挂载情况,可以修改fstab.freescale文件。 * * ..._imx6 分区挂载

【opencv-python】霍夫圆检测_霍夫圆圆心检测python-程序员宅基地

文章浏览阅读6.7k次,点赞10次,收藏55次。霍夫变换检测直线的原理是利用累加器找到最大的(ρ,θ)(ρ,θ)(ρ,θ)数对,如文章所述。圆形的数学表达式为(x−xcenter)2+(y−ycenter)2=r2(x-x_{center})^2+(y-y_{center})^2=r^2(x−xcenter​)2+(y−ycenter​)2=r2,其中(xcenter,ycenter)(x_{center},y_{center})(xcenter​,ycenter​)为圆心坐标,rrr为圆的直径。因此可知一个圆需要xcenter,ycenter,rx_{_霍夫圆圆心检测python

码仔精选,Android面试题-程序员宅基地

文章浏览阅读171次。码个蛋(codeegg) 第 822次推文码妞看世界1.Java创建对象的几种方式使用new关键字使用Class类的newInstance方法使用Constructor类的newIn..._码个蛋 《每日一道面试题》 第一期

Milking Time (poj 3616 简单DP)_poj milking time-程序员宅基地

文章浏览阅读2.5k次,点赞3次,收藏5次。题意:给个时间长度n,m个工作时间段和每个时间段能完成的工作量,一次只能做一个工作并且一旦开始做就要把它做完,要求选择的两个工作时间段之间至少相差r时间(中间需要休息嘛)求选择那些工作n时间内能完成的最大工作量。输出最大值。思路:先按工作的结束时间从小到大排序,再动态规划。dp[i]表示从头开始取到第i段所获得的最大值。二重循环,如果第i段之前的某个段的结束时间加上r小于等于第i段的开始时间,则更新dp[i]。_poj milking time

GDCM:gdcm::Global的测试程序_gbcm main show main screen-程序员宅基地

文章浏览阅读333次。GDCM:gdcm::Global的测试程序GDCM:gdcm::Global的测试程序GDCM:gdcm::Global的测试程序#include "gdcmGlobal.h"#include "gdcmDicts.h"#include "gdcmDict.h"#include "gdcmDefs.h"int TestGlobal(int, char *[]){ // case 1 // Get the global singleton: gdcm::Trace::DebugOn_gbcm main show main screen

理解 OAuth 2.0_shanks user-agent-程序员宅基地

文章浏览阅读278次。转载自http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html作者:阮一峰日期:2014年5月12日OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749。更新:我后来又写了一组三篇的《OAuth 2.0 教程》,更加通俗,并带有代码实例,欢迎阅读。一、应用场景..._shanks user-agent