Когда сокет вашего сервера получает попытки соединения от клиента, s.accept() возвращает объект сокета и IP, порт Информация. Что вам нужно сделать, это сохранить этот новый объект сокета в списке и опросить этот список.
while True:
c, addr = s.accept()
clients.append(c)
pressed = 0
Или еще лучше, использовать словарь по IP: кортеж порта, и перебирать clients.iteritems()
while True:
c,addr = s.accept()
clients[addr] = c
Наивный реализация может быть:
import socket
clients={}
server = socket.socket()
host = socket.gethostname()
port = 12349
s.bind((host, port))
s.listen(5)
while True:
c, addr = server.accept()
clients[addr] = c
pressed = 0
for eachsocket, eachaddrtuple in clients.iteritems():
print 'receiving data from %s'%eachaddrtuple
data = c.recv(1024)
if data:
print data
pressed = pressed + 1
print data, 'pressed count', pressed
Однако , проблема с этой реализацией заключается в том, что каждый цикл блока while в True приведет к блокирующему вызову server.accept(), что означает, что он будет вращаться в этой строке до тех пор, пока не подключится новый клиент. Кроме того, вызов c.recv (1024) также блокирует, что означает, что если у вас 15 клиентов, каждый клиент должен будет отправить данные до повторения цикла снова.
Например, если у вас есть два клиента, и один клиент не отправляет данные в течение минуты, другой клиент фактически отключается. Буфер может переполнять и блокировать отправку, и могут возникнуть другие различные неприятные вещи.
Существует способ, чтобы эти аргументы выполнялись асинхронно, но это ускользает от меня прямо сейчас. Хорошая вещь об асинхронных вызовах заключается в том, что она позволит вам обрабатывать несколько клиентов с правильной проверкой ошибок для получения не полученных данных. Однако это не очень хорошо масштабируется для среднего числа клиентов на одном сервере.
Один из способов преодолеть это, по крайней мере, на машинах Linux (и windows, только сокетами) - использовать модуль «select» python. Модуль выбора, чтобы перефразировать, будет проверять сокеты для любых ожидающих соединений или данных.
Более надежный сервер, который может работать с несколькими клиентами заключается в следующем:
import select
import socket
import sys
host = 'localhost' # what address is the server listening on
port = 50000 # what port the server accepts connections on
backlog = 5 # how many connections to accept
maxsize = 1024 # Max receive buffer size, in bytes, per recv() call
#now initialize the server and accept connections at localhost:50000
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input = [server,] #a list of all connections we want to check for data
#each time we call select.select()
running = 1 #set running to zero to close the server
while running:
inputready,outputready,exceptready = select.select(input,[],[])
for s in inputready: #check each socket that select() said has available data
if s == server: #if select returns our server socket, there is a new
#remote socket trying to connect
client, address = server.accept()
input.append(client) #add it to the socket list so we can check it now
print 'new client added%s'%str(address)
else:
# select has indicated that these sockets have data available to recv
data = s.recv(maxsize)
if data:
print '%s received from %s'%(data,s.getsockname())
#Uncomment below to echo the recv'd data back
#to the sender... loopback!
#s.send(data)
else: #if recv() returned NULL, that usually means the sender wants
#to close the socket.
s.close()
input.remove(s)
#if running is ever set to zero, we will call this
server.close()
Это позволяет нам иметь три списка. Один для входов, один для выходов и один для исключений. Игнорировать исключения на данный момент. В каждом цикле select.select вернет три списка с любыми объектами, ожидающими чтения или записи новых данных.
Таким образом, каждый раз, когда сокет сервера получает попытку подключения, он возвращается «select» в списке «inputready». Аналогичным образом, все клиенты, которые отправили данные на сервер, будут возвращены в том же списке «inputready», поэтому вы должны проверить, какой сокет был возвращен для надлежащего обращения.
Примечание. Первоначально созданный вами серверный сокет используется только для обработки входящих попыток подключения.
Существуют фреймы python, такие как Twisted, которые позволяют создавать простые серверы по настройкам с несколькими параметрами, но я не знаком с ним. Возможно, стоит заглянуть в нее, поскольку программирование сокетов низкого уровня очень неумолимо.
Отметим, что в этой структуре, описанной выше, отключается и отправляется с сервера клиентам, хотя это может быть реализовано. Разъединения сигнализируются с одного конца, отправляя пакет с данными длины 0. Таким образом, вызов c.recv() возвращает пустую строку.
Почти статья! – Matarata