Pertanyaan Saya membutuhkan server untuk mengirim pesan ke semua klien (Python, soket)


Ini adalah program server saya, bagaimana cara mengirim data yang diterima dari setiap klien ke setiap klien lainnya?

import socket
import os
from threading import Thread
import thread

def listener(client, address):
    print "Accepted connection from: ", address

    while True:
        data = client.recv(1024)
        if not data:
            break
        else:
            print repr(data)
            client.send(data)

    client.close()

host = socket.gethostname()
port = 10016

s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(3)
th = []

while True:
    print "Server is listening for connections..."
    client, address = s.accept()
    th.append(Thread(target=listener, args = (client,address)).start())

s.close()

5
2017-11-26 00:18


asal


Jawaban:


Jika Anda perlu mengirim pesan ke semua klien, Anda perlu menyimpan koleksi semua klien dalam beberapa cara. Sebagai contoh:

clients = set()
clients_lock = threading.Lock()

def listener(client, address):
    print "Accepted connection from: ", address
    with clients_lock:
        clients.add(client)
    try:    
        while True:
            data = client.recv(1024)
            if not data:
                break
            else:
                print repr(data)
                with clients_lock:
                    for c in clients:
                        c.sendall(data)
    finally:
        with clients_lock:
            clients.remove(client)
            client.close()

Mungkin akan lebih jelas untuk memfaktorkan bagian ini ke dalam fungsi yang terpisah, seperti a broadcast fungsi yang melakukan semua pengiriman.

Bagaimanapun, ini adalah paling sederhana cara melakukannya, tetapi memiliki masalah:

  • Jika satu klien memiliki koneksi yang lambat, semua orang bisa rogging menulis untuk itu. Dan sementara mereka memblokir pada gilirannya untuk menulis, mereka tidak membaca apa pun, sehingga Anda bisa meluap buffer dan mulai melepaskan semua orang.
  • Jika satu klien memiliki kesalahan, klien yang utasnya menulis ke klien itu bisa mendapatkan pengecualian, yang berarti Anda akan memutuskan hubungan dengan pengguna yang salah.

Jadi, solusi yang lebih baik adalah memberi setiap klien antrean, dan penulis thread melayani antrean itu, di samping utas pembaca. (Anda kemudian dapat memperluas ini dengan berbagai cara — membatasi antrean sehingga orang berhenti mencoba berbicara dengan seseorang yang terlalu jauh di belakang, dll.)


Sebagai Anzel menunjukkan, ada a berbeda cara untuk merancang server selain menggunakan utas (atau dua) per klien: menggunakan reaktor yang melipatgandakan semua acara klien.

Python 3.x memiliki beberapa pustaka hebat untuk ini dibangun, tetapi 2.7 hanya memiliki kikuk dan ketinggalan jaman asyncore/asynchat dan tingkat rendah select.

Seperti kata Anzel, Python SocketServer: mengirim ke beberapa klien memiliki jawaban menggunakan asyncore, yang layak dibaca. Tapi saya tidak akan benar-benar menggunakannya. Jika Anda ingin menulis server berbasis reaktor dengan Python 2.x, saya akan menggunakan kerangka pihak ketiga yang lebih baik seperti Memutar, atau menemukan atau menulis yang sangat sederhana yang langsung duduk di select.


8
2017-11-26 00:28