Socket通信的Python實現


      Python中實現socket通信,socket通信的服務端比較復雜,而客戶端非常簡單,所以客戶端基本上都是用sockct模塊實現,而服務

端用有很多模塊可以使用。下面就說一下服務端可使用的模塊。

 

模塊名 簡介 使用情況
socket 最原始,最低端的模塊,如果你想親自體驗socket的整個實現過程,那就用它吧 不用
SocketServer 它把socket的實現進行了很好的封裝,比如server端要為每個TCP連接創建一個新的線程/進程等等,這些你不用關心,它會幫你搞定,用戶的主要工作是寫已連接TCP/UDP的處理方法handle() 比較常用
select 在一個線程/進程中同時監控處理多個已連接好的socket 比較常用
Twisted 很牛逼的一個模塊,功能很強大,已經算是一個框架了 比較常用
其它異步框架

如gevent等

比較常用

 

      下面用上面幾個常用的模塊實現TCP類型socket通信:Client端發送字符串,Server端收到后在數據前加處理線程/進程的id返回,Client端收到后打

印出來。Client端如果輸入的是空字符,那就關閉Client的socket,接着結束該Client進程(它會觸發Server端對應的connected_socket.recv()返回空

字符串,關閉connect_sock。以下都是在Windows上運行通過。如果想結束server或client端,那就直接kill就行了,它會自動釋放占用的所有資源。

1、使用socket模塊

Server(多線程實現)

      在Winows下,子進程的入口參數不是能有socket類對象,詳見http://bugs.python.org/issue11119,所以要想實現多進程比較麻煩;而Linux上沒

有這個問題,在下面代碼的基礎上很小的修改就行實現。Server端監聽TCP連接,對於建立好的每個連接,監聽進程為其創建一個線程/進程,並檢測線程/

進程的狀態,如果已結束,那就進行收尾工作。監聽進程使用的是非阻塞Socket(不是立即返回,有超時),這是因為監聽進程除了處理新連接之外還要檢

查子進程的狀態。如果設定成阻塞,那它將所有已建立的連接POP出來由交由子線程后,就會一直阻塞在accept(),如果一直沒有新的已建立好的連接,那它

就會一直阻塞下去,就沒有辦法檢測子線程的狀態了。所以為了既能檢查已建立的連接隊列又能檢查子進程的狀態,需把該socket設置成非阻塞。handle()是

為每個建立好的連接創建的子線程的入口。

#-*- coding:utf-8 -*-

import socket
import threading

BUFSIZE = 1024
def handle(connected_sock): while True: data = connected_sock.recv(BUFSIZE) if len(data) >0: print 'receive:',data
cur_thread = threading.current_thread() send_data
= '{}:{}'.format(cur_thread.ident,data) connected_sock.sendall(send_data) #用sendall,不要用send,send並不一定發送所有send_data,可能發送了部分就返回了
print 'send:',send_data else: print 'close the connected socket and terminate sub thread' connected_sock.close() break HOST = '' PORT = 12356 ADDR = (HOST,PORT) sub_threads = [] listen_sock = socket.socket() listen_sock.settimeout(5.0) #設定超時時間后,socket其實內部變成了非阻塞,但有一個超時時間 listen_sock.bind(ADDR) listen_sock.listen(2) print 'build connect when new TCP comes' while True: try: connected_sock,client_addr = listen_sock.accept() except socket.timeout: length = len(sub_threads) while length: sub = sub_threads.pop(0) sub_id = sub.ident #進程ID sub.join(0.1) #等待線程結束,0.1秒 if sub.isAlive(): sub_threads.append(sub) else: print 'killed sub thread ',sub_id length -=1 else: t = threading.Thread(target=handle,name='sub thread',args=(connected_sock,)) #它繼承了listen_socket的阻塞/非阻塞特性,因為listen_socket是非阻塞的,所以它也是非阻塞的 #要讓他變為阻塞,所以要調用setblocking connected_sock.setblocking(1) t.start() sub_threads.append(t)

 

Client端

#-*- coding:utf-8 -*-

import socket
HOST = 'localhost'
PORT = 12356
ADDR =(HOST,PORT)
BUFSIZE = 1024

sock = socket.socket()
try:
    a = sock.connect(ADDR)
except Exception,e:
    print 'error',e
    sock.close()
    sys.exit()

print 'have connected with server'

while True:
    data = raw_input('> ')
    if len(data)>0:
print 'send:',data sock.sendall(data) #不要用send() recv_data
= sock.recv(BUFSIZE) print 'receive::',recv_data else: sock.close() break

 2、SocketServer模塊

Server(多線程實現,Linux下建議用多進程)

      在Linux上可以用多進程實現,基本上把下面代碼中的ThreadingTCPServer改為ForkingTCPServer就可以了。在Windows下無法用多進程,因為

SocketServer為每個已連接創建進程時,用的是os.fork(),windows上沒有fork() API,哎,干嘛不搞個兼容Windows的API啊。

      可以看到,下面的代碼非常簡潔,用戶不用去子線程的結束后,父進程對它的收尾,也不用關心socket的關閉。這些都由SocketServer完成。

Handler中的handle()方法與上面用socket模塊寫的handle方法基本相同。

#-*- coding:utf-8 -*-
from SocketServer import BaseRequestHandler,ThreadingTCPServer
import threading

BUF_SIZE=1024

class Handler(BaseRequestHandler):
    def handle(self):
        while True:
            data = self.request.recv(BUF_SIZE)
            if len(data)>0:
                print 'receive=',data
                cur_thread = threading.current_thread()
                response = '{}:{}'.format(cur_thread.ident,data)
                self.request.sendall(response)
                print 'send:',response
            else:
                print 'close'
                break



if __name__ == '__main__':
    HOST = ''
    PORT = 12356
    ADDR = (HOST,PORT)
    server = ThreadingTCPServers(ADDR,Handler)  #參數為監聽地址和已建立連接的處理類
    print 'listening'
    server.serve_forever()  #監聽,建立好TCP連接后,為該連接創建新的socket和線程,並由處理類中的handle方法處理

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM