您好,我能够将我的客户端连接到我的服务器,但它只有一对一的关系(1 个客户端到服务器)。我的问题是我应该怎么做才能将许多客户端连接到我的服务器?有人知道我的情况吗?任何帮助将不胜感激,在此先感谢...以下是我的代码。
服务器.py
import socket
s = socket.socket()
host = socket.gethostname()
port = 12349
s.bind((host, port))
s.listen(5)
while True:
c, addr = s.accept()
pressed = 0
while True:
print 'Got connection from', addr
data = c.recv(1024)
if not data:
break
pressed = pressed + 1
print data, 'pressed count', pressed
客户端.py
import socket
from Tkinter import*
root = Tk()
root.title("ADKOO")
root.geometry("150x80")
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
port = 12349
s.connect((host, port))
def counterPlus():
print "sending to"
s.send('sent by '+host)
app = Frame(root)
app.grid()
button1 = Button(app, text="+", width=15, command=counterPlus)
button1.grid()
root.mainloop()
最佳答案
当您的服务器套接字收到来自客户端的连接尝试时,s.accept() 返回一个套接字对象和 ip、端口信息。您需要做的是将这个新的套接字对象保存在一个列表中并轮询该列表。
while True:
c, addr = s.accept()
clients.append(c)
pressed = 0
或者更好的是,使用 ip:port 元组的字典,并迭代 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:” block 的每个循环都会导致对 server.accept() 的阻塞调用,这意味着它将在该行上自旋循环直到新客户端连接。同样,c.recv(1024) 调用也是阻塞的,这意味着如果您有 15 个客户端,则每个客户端都需要在循环再次迭代之前发送数据。
例如,如果你有两个客户端,一个客户端一分钟不发送数据,另一个客户端实际上被切断了。缓冲区可能会溢出并阻塞发送方,并且可能会发生其他各种令人讨厌的事情。
有一种方法可以将这些参数设置为异步操作,但我现在无法理解。 异步调用的好处在于,它可以让您处理多个客户端,并对未接收到的数据进行适当的错误检查。但是,这对于一台服务器上的中等数量的客户端而言并不能很好地扩展。
克服这个问题的一种方法,至少在 linux 机器上(和 windows,只有套接字)是使用 python 'select' 模块。 选择模块,换句话说,将检查套接字是否有任何等待的连接或数据。
可以处理多个客户端的更强大的服务器如下:
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 将返回三个列表,其中包含任何等待读取或写入新数据的对象。
因此每次服务器套接字接收到连接尝试时,都会由'inputready'列表中的'select'返回。类似地,任何已向服务器发送数据的客户端都将在同一个“inputready”列表中返回,因此您必须检查返回的是哪个套接字以正确处理它。
注意:您最初创建的服务器套接字仅在此处用于处理传入的连接尝试。
有Twisted等python框架允许您通过设置一些参数来创建简单的服务器,但我不熟悉它。这可能值得研究,因为低级套接字编程是非常无情的。
顺便说一句,请注意断开连接和从服务器发送到客户端在上面介绍的这个框架中没有处理,尽管它可以实现。通过发送一个长度为 0 的数据包从一端发出断开信号。所以 c.recv() 调用将返回一个空字符串。
关于python - 客户端到服务器,python中的套接字多对一关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18724126/