關于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。