国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

通過(guò)編寫(xiě)聊天程序來(lái)熟悉python中多線(xiàn)程及socket的用法

2019-11-14 16:57:32
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

1、引言

Python中提供了豐富的開(kāi)源庫(kù),方便開(kāi)發(fā)者快速就搭建好自己所需要的應(yīng)用程序。本文通過(guò)編寫(xiě)基于tcp/ip協(xié)議的通信程序來(lái)熟悉python中socket以及多線(xiàn)程的使用。

2、python中的多線(xiàn)程以及socket的使用

在編寫(xiě)聊天程序程序之前,我們先熟悉一下python中多線(xiàn)程以及socket的使用方法。

2.1、多線(xiàn)程使用方法

在python中提供了Thread這個(gè)類(lèi)來(lái)實(shí)現(xiàn)多線(xiàn)程程序的開(kāi)發(fā)。

Thread類(lèi)的原型如下:

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

構(gòu)造函數(shù)能帶有關(guān)鍵字參數(shù)被調(diào)用。這些參數(shù)是:

group 應(yīng)當(dāng)為 None,為將來(lái)實(shí)現(xiàn)Python Thread類(lèi)的擴(kuò)展而保留。

target 是被 run()方法調(diào)用的回調(diào)對(duì)象. 默認(rèn)應(yīng)為None, 意味著沒(méi)有對(duì)象被調(diào)用。

name 為線(xiàn)程名字。默認(rèn),形式為'Thread-N'的唯一的名字被創(chuàng)建,其中N 是比較小的十進(jìn)制數(shù)。

args是目標(biāo)調(diào)用參數(shù)的tuple,默認(rèn)為()。

kwargs是目標(biāo)調(diào)用的參數(shù)的關(guān)鍵字dictionary,默認(rèn)為{}。

而Thread類(lèi)還提供了很多方法,而本文只講述程序中所需要的1個(gè)方法,其他的方法讀者可以根據(jù)需要去查閱python的官方幫助文檔。

start():開(kāi)啟一個(gè)線(xiàn)程

下面將通過(guò)一段簡(jiǎn)單的程序來(lái)實(shí)驗(yàn)Thread的使用。

程序如下:

  

import threading def  PRint_work(cunt):    for i in range(cunt):        print 'new thread print:',idef  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()    

 

程序比較簡(jiǎn)單,就不多做解釋?zhuān)贿^(guò)有2點(diǎn)需要值得注意。

注意:

1、在使用Thread類(lèi)的時(shí)候需要import threading

2、當(dāng)多線(xiàn)程啟動(dòng)的方法的參數(shù)只有一個(gè)參數(shù)的時(shí)候,實(shí)例化Thread的args的參數(shù)要表示為(param1,)需要在參數(shù)后面打一個(gè)逗號(hào),這是因?yàn)閠uple元組只有一個(gè)元素的時(shí)候需要在后面加一個(gè)逗號(hào),防止歧義。

2.2、socket的使用方法

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

注意:

1 在python中使用socket時(shí)要import socket

2 在使用socket中又服務(wù)器端和客戶(hù)端之分

 

服務(wù)器:

1、建立一個(gè)基于tcp協(xié)議的socket類(lèi)

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

其中AF_INET指定的ipv4的協(xié)議,也可以使用AF_INET6指定ipv6的協(xié)議,而STREAM是指定面向流的tcp協(xié)議。

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

綁定一個(gè)端口號(hào),其中'127.0.0.1'是客戶(hù)端的ip地址,可以使用’0.0.0.0’來(lái)綁定網(wǎng)絡(luò)中所有的ip,8089是指定的端口,其中端口在小于1024的時(shí)候需要有管理員的權(quán)限才能綁定。

3、s.listen(5)

開(kāi)始實(shí)行監(jiān)聽(tīng)參數(shù):代表連接的最大數(shù)量

4、sock, addr = s.accept()

接受一個(gè)客戶(hù)端的連接,返回的是一個(gè)與客戶(hù)端保持連接的socket對(duì)象以及客戶(hù)端的ip地址和端口。該方法也會(huì)阻塞線(xiàn)程,直到獲得客戶(hù)端的連接。

 

客戶(hù)端:

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

連接到服務(wù)器,其中'www.baidu.com’也可以是服務(wù)器的ip地址。

2、s.send('hello')

發(fā)送數(shù)據(jù)’hello’。TCP連接創(chuàng)建的是雙向通道,雙方都可以同時(shí)給對(duì)方發(fā)數(shù)據(jù)。但是誰(shuí)先發(fā)誰(shuí)后發(fā),怎么協(xié)調(diào),要根據(jù)具體的協(xié)議來(lái)決定。

3、s. recv(1024)

接受連接的對(duì)方發(fā)來(lái)的數(shù)據(jù)。該方法會(huì)阻塞當(dāng)前線(xiàn)程,所以需要一個(gè)專(zhuān)門(mén)的線(xiàn)程來(lái)接受數(shù)據(jù)。

注意:

同一個(gè)端口,被一個(gè)Socket綁定了以后,就不能被別的Socket綁定了。

3、基于python的聊天程序的流程設(shè)計(jì)

在第二點(diǎn)講述了聊天程序需要用到的知識(shí)點(diǎn),以及需要注意的地方,現(xiàn)在我們就開(kāi)始來(lái)設(shè)計(jì)程序的流程吧。

把程序分為即服務(wù)器與客戶(hù)端兩個(gè)部分。

服務(wù)器端的流程如下圖:

 

其中user對(duì)象代表一個(gè)客戶(hù)端的連接。

類(lèi)結(jié)構(gòu)如下圖所示:

 

客戶(hù)端的流程設(shè)計(jì)如下圖:

 

4、聊天程序的編碼過(guò)程

  該程序?qū)崿F(xiàn)的是一個(gè)相對(duì)比較簡(jiǎn)單的聊天程序,由于是基于控制臺(tái)實(shí)現(xiàn)的,所只設(shè)計(jì)容許兩個(gè)人聊天,另外消息的編碼的分割符為|

  4.1、服務(wù)器端

  首先建立一個(gè)User的數(shù)據(jù)結(jié)構(gòu),代碼如下:

import socket class User:    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()

 

  

  服務(wù)端的編碼如下:

import sys import socketimport threading,timeimport User#global variableuserlist=[]    def hand_user_con(usr):    try:        isNormar=True        while isNormar:            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])#發(fā)送消息給目標(biāo)用戶(hù),參數(shù)1:目標(biāo)用戶(hù),參數(shù)2:消息內(nèi)容            if msg[0]=='exit':                print 'user [%s] exit' % msg[0]                isNormar=False                usr.close()                userlist.remove(usr)    except:        isNormar=False        #通知其他用戶(hù)以上的好友       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 in userlist:        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...'    while True:        sock,addr=s.accept()#等待用戶(hù)連接        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、客戶(hù)端  

  客戶(hù)端的編碼如下:

import sys import socketimport threading,time#global variable    isNormar=Trueother_usr=''def recieve_msg(username,s):    global isNormar,other_usr    print 'Please waiting other user login...'    s.send('login|%s' %username)    while(isNormar):        data= s.recv(1024)#阻塞線(xiàn)程,接受消息        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():     global isNormar,other_usr      try:        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=False    finally:        pass    while isNormar:        msg=raw_input()#接受用戶(hù)輸入        if msg=="exit":            isNormar=False        else:            if(other_usr!=''):                s.send("talk|%s|%s" % (other_usr,msg))#編碼消息并發(fā)送    s.close()    if __name__=="__main__":    main()

  其效果截圖如下:

5、結(jié)論

  通過(guò)編寫(xiě)該聊天的程序,了解了python中多線(xiàn)程以及socket的使用。該聊天的程序過(guò)于簡(jiǎn)單,僅僅只是實(shí)現(xiàn)了這客戶(hù)端-服務(wù)端-客戶(hù)端信息交互的一個(gè)流程,并不是很完善,在很多地方還存在很多異常。

  


發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿巴嘎旗| 云阳县| 永年县| 板桥市| 金湖县| 禄劝| 横山县| 义乌市| 阜城县| 聂拉木县| 巴林右旗| 浮梁县| 日照市| 百色市| 丹寨县| 连南| 宜兰市| 无棣县| 威海市| 沅江市| 朝阳市| 迭部县| 富裕县| 神木县| 抚宁县| 南康市| 福贡县| 大同县| 新密市| 沾益县| 堆龙德庆县| 吕梁市| 通州市| 莆田市| 平阴县| 枣强县| 常熟市| 肥西县| 三台县| 灵台县| 友谊县|