2011-07-16 30 views
7

Bana mı python'da engelleme olmayan soketler hakkında iyi bir öğretici bulamıyorum?Python'da engellenmeyen soket mi?

İçinde .recv ve .send tam olarak nasıl çalıştığından emin değilim. Python belgelerine göre, (en azından anlamış olmak üzere) recv 'ed veya send' verileri yalnızca kısmi veriler olabilir. Yani bu, bir şekilde recv numaralı verileri birleştirmek zorunda olduğumu ve tüm verilerin send içinde gönderilmesini sağladığım anlamına geliyor. Öyleyse nasıl? Bir örnek çok takdir edilecektir.

+5

http://www.doughellmann.com/PyMOTW/select/ – Epeli

+0

Muhtemelen send() ve sendall() arasında ayrım yapmak istersiniz. http://tarekziade.wordpress.com/2011/07/12/firefox-sync-python/ Ayrıca büyük olasılıkla bazı üst düzey senkronize olmayan IO altyapısını kullanmak isteyebilirsiniz: Eventlet: http://eventlet.net/ –

cevap

8

Soketinizin engelleyici olmayan bir modda olup olmadığı gerçekten önemli değil; recv/gönderme işlemi hemen hemen aynı; Tek fark, engelleme olmayan soketin veri/soket beklemek yerine 'Geçici olarak geçici olarak kullanılamaz' hatası vermesidir.

recv yöntemi, alınan bayttan daha az veya eşit olduğu söylenen alınan bayt sayısını döndürür.

def recvall(sock, size): 
    data = '' 
    while len(data) < size: 
    d = sock.recv(size - len(data)) 
    if not d: 
     # Connection closed by remote host, do what best for you 
     return None 
    data += d 
    return data 

Bu mod engelleme tam olarak aynı yapmak zorunda, hatırlamak önemlidir: Tam olarak boyut bayt almak istiyorsanız, aşağıdaki koda benzer bir şey yapmalıdır. (Uygulama katmanına iletilmektedir bayt sayısı OS recv tampon boyutu ile sınırlıdır, örneğin içindir.)

gönderme yöntem geçen şeridin uzunluğuna az ya da eşit olduğu söylenir gönderilen bayt sayısını, . Bir istisna hata (belgelere göre)

def sendall(sock, data): 
    while data: 
    sent = sock.send(data) 
    data = data[sent:] 

Sen sock.sendall doğrudan kullanabilirsiniz, ancak yapabilirsiniz: gönderildiği mesajın tamamını sağlamak istiyorsanız, aşağıdaki koda benzer bir şey yapması gerektiğini kaldırdı ve varsa, ne kadar veri başarıyla gönderildiğini belirlemenin bir yolu yoktur.

Python'daki yuvalar BSD soketi API'sini takip eder ve c tarzı soketlere benzer şekilde davranır (fark, örneğin, hata kodunu döndürmek yerine istisna atar). Web ve man sayfaları üzerinde herhangi bir soket öğretici ile mutlu olmalısınız.

+0

@ultimatebuster'i kabul ettiğiniz için teşekkür ederim, 'recvall'daki hata işleminin çok iyi olmadığını ve kapalı bağlantıların üstesinden gelmek için d değilse de ekledim. – tomasz

0

Bir arabelleğe göndermek istediğiniz baytları saklayın. (Onları birleştirmek zorunda değilsiniz çünkü bayt dizeleri listesi, iyi olurdu.) Engellenmeyen modunda soket ayarlamak için fcntl.fcntl işlevini kullanın:

import fcntl, os 
fcntl.fcntl(mysocket, fcntl.F_SETFL, os.O_NONBLOCK) 

Sonra select.select bunu size söyleyecektir Sokete okumak ve yazmak tamam. (Tamamlanmadığında yazma, engelleme modunda EAGAIN hatasını verecektir.) Yazarken, kaç bayt yazıldığını görmek için dönüş değerini kontrol edin. Tamponundan o kadar çok bayta sahip ol. Dizeler dizesi yaklaşımını kullanırsanız, her seferinde ilk dizeyi yazmayı denemeniz gerekir.

Boş dizeyi okursanız, soketiniz kapalı.

+0

Ayrıca mysocket.setblocking (0) '] (https://docs.python.org/2/library/socket.html#socket.socket.setblocking). –