客户端到服务器,在python中的socket多对一关系

gad*_*dss 4 python sockets multiprocessing many-to-one

嗨,我能够将我的客户端连接到我的服务器,但它只有一对一的关系(1个客户端到服务器).我的问题是我应该怎么做才能将许多客户端连接到我的服务器?有没有人对我的情况有所了解?任何帮助将不胜感激,提前感谢...以下是我的代码.

server.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
Run Code Online (Sandbox Code Playgroud)

client.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()
Run Code Online (Sandbox Code Playgroud)

gre*_*212 13

当服务器的套接字从客户端收到连接尝试时,s.accept()返回套接字对象和ip,端口信息.您需要做的是将此新套接字对象保存在列表中并轮询此列表.

while True:
    c, addr = s.accept()
    clients.append(c)
    pressed = 0
Run Code Online (Sandbox Code Playgroud)

或者更好的是,使用ip:port tuple的字典,并遍历clients.iteritems()

while True:
    c,addr = s.accept()
    clients[addr] = c
Run Code Online (Sandbox Code Playgroud)

一个天真的实现可能是:

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
Run Code Online (Sandbox Code Playgroud)

但是,这个实现的问题是'while True:'块的每个循环都会导致对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()
Run Code Online (Sandbox Code Playgroud)

这允许我们有三个列表.一个用于输入,一个用于输出,一个用于例外.暂时忽略异常.在每个循环中,select.select将返回三个列表,其中任何对象都在等待读取或写入新数据.

因此,每次服务器套接字收到连接尝试时,它都将通过'inputready'列表中的'select'返回.同样,任何已向服务器发送数据的客户端都将在相同的"inputready"列表中返回,因此您必须检查以确定返回哪个套接字以正确处理它.

注意:您最初创建的服务器套接字仅用于处理传入连接尝试.

有一些python框架,如Twisted,允许你通过设置一些参数来创建简单的服务器,但我不熟悉它.值得研究一下,因为低级套接字编程是非常不可原谅的.

另外,请注意,虽然可以实现,但是在上面提到的此框架中不会处理从服务器到客户端的断开连接和发送.通过发送具有0长度数据的分组从一端发信号通知断开连接.所以c.recv()调用将返回一个空字符串.