日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自己实现多线程的socket,socketserver源码剖析

發布時間:2024/4/17 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自己实现多线程的socket,socketserver源码剖析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1,IO多路復用

三種多路復用的機制:select、poll、epoll

用的多的兩個:select和epoll

簡單的說就是:
1,select和poll所有平臺都支持,epoll只有linux支持
2,select效率不高,epoll效率高
3,IO多路復用用來監聽socket對象內部是否變化
4,要調用select模塊

?

什么是文件描述符:

當程序打開一個現有文件或者創建一個新文件時,內核向進程返回一個文件描述符。文件描述符的有效范圍是 0 到 OPEN_MAX

linux查看OPEN_MAX的方法:ulimit -n。linux默認最大文件描述符為1024,一般可以將它改為65535,可以使用命令ulimit -HSn ?65535。也可以保存到/etc/security/ulimit.conf里

?

?

?

?

python的select函數:

?

def select(rlist, wlist, elist, timeout=None)->(rl,wl,el)

rlist獲取變化的句柄添加到rl中

只要wlist有句柄,都放到wl中

當elist某個句柄發生錯誤時,放到el中

timeout,如果沒有設置超時時間,select一直會卡著,如果設置timeout=1,表示句柄沒有變化時,select會卡1秒,一有變化就執行

?

在socket中

select用來監聽sk連接時候的句柄和收發數據的句柄

import socket import select sk=socket.socket() sk.bind(("127.0.0.1",9999)) sk.listen(2) inputs=[sk] outputs=[] msg={} while True:rlist,wlist,e=select.select(inputs,outputs,[],1)print(len(inputs),len(rlist),len(wlist),len(outputs))'''只要有連接進來,就接收,只要有收發消息的句柄發生變化,就收消息,收到消息后可以不直接發送,存到outputs里,wlist==outputs,只要outputs里有句柄,就交給wlist去循環發送'''for r in rlist:if r==sk:conn,addr=r.accept()inputs.append(conn)else:try:rt=r.recv(1024)outputs.append(r)print(rt)msg.setdefault(r, [])msg[r].append(rt)except:inputs.remove(r)del msg[r]#上面如果沒有數據,這邊就一直發數據給客戶端,直到客戶端接收消息,得到的是一大串for w in wlist:for m in msg[w]:w.sendall(m)outputs.remove(w) #所以發送完這邊要刪除句柄,解決了無限發數據的問題

?

socketserver源碼剖析

通過上面的實驗得出規律:一開始建立socket對象到listen這幾步都沒變,直到accept之間在循環使用select檢查sk是否變化,如果有新鏈接進來就accept,之后就能通信了。

import socketserverclass MyServer(socketserver.BaseRequestHandler):def handle(self):# print self.request,self.client_address,self.serverconn = self.requestwhile True:recv_data=conn.recv(5)conn.sendall(recv_data)if __name__ == '__main__':server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer)print(server.server_address)server.serve_forever() 這是socketserver服務器端實現代碼

第一步:建立socket對象到listen這幾步肯定在創建構造函數的時候已經做掉了。

第二步:因為它是多線程,select查看有sk變動后,每次有連接進來就分配一個線程給sk,然后accept連接

第三步:在accept之后調用socketserver.BaseRequestHandler來收發消息,在調用MySocket的handle,也就是調用BaseRequestHandler的handle

第四步:forever()

ThreadingTCPServer的繼承關系:

?

?

?

import socket import select import threadingdef handle(sk):'''此處發送'''sk.sendall(bytes("hello",encoding="utf-8"))sk=socket.socket() sk.bind(("127.0.0.1",9999)) sk.listen(5) while True:rlist,w,e=select.select([sk],[],[],1)for r in rlist:conn,addr=r.accept()th=threading.Thread(target=handle,args=(conn,))th.daemon=Falseth.start() sk.close() socketserver簡化 import socketsk=socket.socket() sk.connect(("127.0.0.1",9999)) print(sk.recv(1024)) sk.close() client

?

轉載于:https://www.cnblogs.com/euewrqe/p/5880052.html

總結

以上是生活随笔為你收集整理的自己实现多线程的socket,socketserver源码剖析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。