【问题标题】:client to server, socket in python many to one relationship客户端到服务器,python中的套接字多对一关系
【发布时间】:2013-09-10 16:19:50
【问题描述】:

您好,我能够将我的客户端连接到我的服务器,但它只有一对一的关系(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

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()

【问题讨论】:

    标签: python sockets multiprocessing many-to-one


    【解决方案1】:

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

    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:' 块的每个循环都会导致对 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 将返回三个列表,其中包含等待读取或写入新数据的任何对象。

    所以每次服务端socket收到一个连接尝试,都会被'inputready'列表中的'select'返回。类似地,任何向服务器发送数据的客户端都将在同一个“输入就绪”列表中返回,因此您必须检查返回哪个套接字以正确处理它。

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

    有像Twisted这样的python框架,可以让你通过设置一些参数来创建简单的服务器,但我不熟悉。这可能值得研究,因为低级套接字编程非常无情。

    顺便说一句,请注意,从服务器到客户端的断开连接和发送不在上面介绍的这个框架中处理,尽管它可以实现。通过发送长度为 0 的数据包从一端发出断开信号。所以 c.recv() 调用会返回一个空字符串。

    【讨论】:

    • 几乎是一篇文章!
    【解决方案2】:

    您可以为“多对一”概念安排您的服务器

    示例 tcp 服务器代码

    import socket
    import threading
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind(("0.0.0.0", 4444))
    
    def connection_process(connection):
        connection.settimeout(360)
        while True:
    
            try:
                byteSensorData=connection.recv(1024)
                print("client data: {}".format(byteSensorData))
                print("do something for clients")
                response="send something"
                connection.send(response.encode('utf-8'))
            except socket.timeout:
                connection.close()
                break
            except Exception as e:
                print(e)
                connection.close()
                break
    while True:
        try:
            s.listen(2)
            connection, addr = s.accept()
            x = threading.Thread(target=connection_process, args=(connection,))
            x.start()
        except Exception as e:
            connection.close()
    

    【讨论】:

      猜你喜欢
      • 2014-11-05
      • 2012-06-09
      • 1970-01-01
      • 2013-11-11
      • 1970-01-01
      • 2017-02-25
      • 1970-01-01
      • 2015-03-09
      • 2021-12-08
      相关资源
      最近更新 更多