socket,queue

關于socket,queue以及多線程的總結

一、socket服務器

#socketserve.py
import OpenOPC
import socket
import struct
import Queue
import json
import time
import threading

def readHuiluTags(alist,adict,opc,queueObject):
    while True:
      temp=opc.read(alist)
      for i in range(len(temp)):
          adict[temp[j][0]]=temp[j][1]
      queueObject.put(adict)
       block為可選參數,默認為True,如果當前隊列為空且block為1,put()方法就使調用線程暫停,直到空出一個數據單元,如果block為Flase,put方法將引發(fā)Full異常,timeout為等待時間,None為一直等下去,0為不等待,正數n為等待n秒還不能存入,報異常。



serve=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #創(chuàng)建socket對象
serve.bind(('192.168.1.80',8080))  #綁定地址和端口
地址和端口以元組的形式輸入,通常地址可以寫為'localhost'
serve.listen(5)  #讓socket服務器進入監(jiān)聽狀態(tài)
輸入的參數并不代表可以連接的最大客戶端數目是五個,它代表的是加入你服務器可以承載的客戶端連接數量是100個,
那該服務器最大可以使5個客戶端排隊等待。當有第106個客戶端連接進來的時候就會報錯。


while True:
    con,address=serve.accept() #阻塞式連接:表示服務器端運行到這里會等待,當客戶端連接進來的時候,程序再繼續(xù)往下運行
    該方法返回的是一個元組tuple,con是返回的當前連接的客戶端對象
    clientId=con.recv(1024)    #接收客戶端發(fā)送到服務器的數據
    socket服務器與客戶端傳遞數據是以二進制的格式進行傳遞的,所以無論在服務器端還是在客戶端,想要發(fā)送和接收的數據都需要進行轉換
    if cilentId='K01':
        huiluNum=2
        tagsNameAll=json.loads(con.recv(1024)) 因為傳遞過來的數據是一個字符串,所以得用json.loads進行轉換
        threadList=[]
        giveToclient=Queue.LifoQueue(maxsize=0)  創(chuàng)建一個隊列用于存儲所有標簽及對應數據的字典
        LifoQueue是后入先出的隊列,Queue是先入先出的隊列,
        maxsize這個參數表示隊列里面可以存儲數據的最大個數,maxsize<=0表示無限制
        allTagsValue={}
        temp=threading.Thread(target=函數名,args=(該函數需要的參數)
        threadList.append(temp)
        while True:
            temp1=giveToClient.get(block=True,timeout=None)  調用隊列對象的get()方法從隊尾刪除并返回一個項目
            可選參數為block,默認為True,如果隊列為空且block為True,get()就使調用線程暫停,直至有項目可用,如果隊列為空且block為Flase,隊列將引發(fā)Empty異常,timeout為等待時間,None為一直等下去,0為不等待,正數n為等待n秒還不能讀取,報異常。
            con.send(json.dumps(temp1).encode('gbk')) 發(fā)送的數據必須為二進制的
            refPvDict=[]
            valueList=[]
            for key in refPvDict:
                pvList.append(key)
            for key in refPvDict.values():
                valueList.append(value)
            for i  in range(huiluNum):
                opc.write((pvList[i],valueList[i]))
    con.close()
serve.close()

在進行多線程的編程中,我們需要在主線程中創(chuàng)建隊列進行主線程和子線程的通訊,所以在子線程最好創(chuàng)建隊列來存儲數據,這樣創(chuàng)建出來的隊列的數據沒有辦法和主線程及其他線程共享,另外最好不要在子線程中修改主線程中隊列里面的數據。子線程的優(yōu)勢在于,只是從主線程的隊列里面的拿數據,并向主線程的隊列返回數據。


另外,以共有三種模式的隊列可以創(chuàng)建。

一是先入先出模式,queue.Queue(),即隊列中的數據按順序存儲在隊列中,從隊列中取數據的時候也是按順序取,取完一個就在隊列里面刪除取走的那個。
二是后入先出模式,queue.LifoQueue()即隊列中的數據按順序存儲在隊列中,從隊列中取數據的時候取最后一個數據。


三是設置優(yōu)先級模式,還未學習,等待補充

二、socket客戶端

import socket
import struct
import json
import threading
import queue
import time
import numpy as np

#定義PIDcontrol
def PIDcontrol(queueObject,refName,pvName,adict,Kp=0.6,Ki=0.3,Kd=0,u1=0,Ee=0):
    while True:
        temp=queueObject.get(block=True,timeout=None)
        a=Kp*temp[pvName]+Ki*u1+int(np.random.rand(1,1)[0])
        e=temp[refName]-a
        u=e+Ee
        u1=u
        Ee=Ee+e
        adict[pvName]=a
    return

def dividehuilu(queue,anotherlist,alist):
    while True:
        newdict={}
        adict=queue.get(block=True,timeout=None)
        for i in anotherlist:
            for key in adict:
                if i == key:
                    newdict[i]=adict[key]
        print(type(adict)) 
        temp1=[]
        temp2=[]
        temp3={}
        temp4={}
        for key in newdict:
            temp1.append(key)
        for value in newdict.values():
            temp2.append(value)
        for i in range(2):
            temp3[temp1[i]]=temp2[i]
            temp4[temp1[i+2]]=temp2[i+2]
        print(temp1,temp2,temp3,temp4)
        alist[0].put(temp3)
        alist[1].put(temp4)

def readLoop(socketObject,queueObject):
    while True:
        temp=json.loads(socketObject.recv(1024).decode('gbk'))
        queueObject.put(temp)

#配置socket客戶端
clientK01=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientK01.connect(('192.168.1.80',8080))
#客戶端的任務
#任務一:提供工序名字
clientId='K01'.encode('gbk')
#任務二:告訴服務器我需要的相應的標簽的值
tagsName=['[L01]huilu1_sp','[L01]huilu1_ref','[L01]huilu2_sp','[L01]huilu2_ref']
#任務三:說明該工序有幾個回路
huiluNum=2
huilu1=['[L01]huilu1_sp','[L01]huilu1_ref']
huilu2=['[L01]huilu2_sp','[L01]huilu2_ref']
valuesAll=queue.LifoQueue()
threadList=[]
queueList=[]
refPvDict={}
clientK01.send(clientId)
#發(fā)送需要的標簽名給服務器
clientK01.send(json.dumps(tagsName).encode('gbk'))
#接收服務器發(fā)來的字典數據:標簽名為鍵,標簽值為值,這個得循環(huán)的讀,因為有更新
readValueLoop=threading.Thread(target=readLoop,args=(clientK01,valuesAll))
threadList.append(readValueLoop)
readValueLoop.start()
#tagsValueDict=clientK01.recv(1024)
#tagsValueDict=json.loads(tagsValueDict)
#print(tagsValueDict)
for i in range(huiluNum):
    huiluQueue=queue.LifoQueue(maxsize=0)
    queueList.append(huiluQueue)
readHuiluQueue=threading.Thread(target=dividehuilu,args=(valuesAll,tagsName,queueList))
threadList.append(readHuiluQueue)
readHuiluQueue.start()
PIDhuilu1=threading.Thread(target=PIDcontrol,args=(queueList[0],'[L01]huilu1_sp','[L01]huilu1_ref',refPvDict))
threadList.append(PIDhuilu1)
PIDhuilu1.start()
PIDhuilu2=threading.Thread(target=PIDcontrol,args=(queueList[1],'[L01]huilu2_sp','[L01]huilu2_ref',refPvDict))
threadList.append(PIDhuilu2)
PIDhuilu2.start()
for i in threadList:
    i.join(2)
#join函數表示每個線程執(zhí)行兩秒后再進行主程序的執(zhí)行
while True:
    time.sleep(5)
    #print(refPvDict)
    clientK01.send(json.dumps(refPvDict).encode('gbk'))
clientK01.close()

注意:用socket一次只能和一個客戶端進行交互,其余的客戶端要交互需要排隊等候,等前面的斷開。所以我們想連接多個客戶端就要用socketserver。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,656評論 1 32
  • 最全的iOS面試題及答案 iOS面試小貼士 ———————————————回答好下面的足夠了-----------...
    zweic閱讀 2,803評論 0 73
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,575評論 0 35
  • __block和__weak修飾符的區(qū)別其實是挺明顯的:1.__block不管是ARC還是MRC模式下都可以使用,...
    LZM輪回閱讀 3,594評論 0 6
  • 色難,是一個形容詞,意思是(對父母)和顏悅色,是最難的。源于子夏問孝。 偶爾會對爸媽說,他們老了我可以...
    時光不舊落塵新閱讀 274評論 0 2

友情鏈接更多精彩內容