为什么主机中止连接?

时间:2009-09-24 16:44:28

标签: python networking

我正在教自己Python网络,我回想起当我自学线程时,我遇到this page,所以我复制了脚本,为Python 3.1.1更新了它们并运行它们。他们工作得很好。

然后我做了一些修改。我的目标是做一些简单的事情:

  1. 客户端挑选一个整数并将其发送到服务器。
  2. 服务器接收腌制整数,取消它,加倍,然后将其腌制并发送回客户端。
  3. 客户端接收pickle(和doubled)整数,取消它并输出它。
  4. 这是服务器:

    import pickle
    import socket
    import threading
    
    class ClientThread(threading.Thread):
        def __init__(self, channel, details):
            self.channel = channel
            self.details = details
            threading.Thread.__init__ ( self )
    
        def run(self):
            print('Received connection:', self.details[0])
            request = self.channel.recv(1024)
            response = pickle.dumps(pickle.loads(request) * 2)
            self.channel.send(response)
            self.channel.close()
            print('Closed connection:', self.details [ 0 ])
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('', 2727))
    server.listen(5)
    
    while True:
        channel, details = server.accept()
        ClientThread(channel, details).start()
    

    这是客户:

    import pickle
    import socket
    import threading
    
    class ConnectionThread(threading.Thread):
        def run(self):
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            client.connect(('localhost', 2727))
    
            for x in range(10):
                client.send(pickle.dumps(x))
                print('Sent:',str(x))
                print('Received:',repr(pickle.loads(client.recv(1024))))
    
            client.close()
    
    for x in range(5):
        ConnectionThread().start()
    

    服务器运行正常,当我运行客户端时,它成功连接并开始发送整数并按预期接收它们。然而,它很快就被排除在外:

    Exception in thread Thread-2:
    Traceback (most recent call last):
      File "C:\Python30\lib\threading.py", line 507, in _bootstrap_inner
        self.run()
      File "C:\Users\Imagist\Desktop\server\client.py", line 13, in run
        print('Received:',repr(pickle.loads(client.recv(1024))))
    socket.error: [Errno 10053] An established connection was aborted by the softwar
    e in your host machine
    

    服务器继续运行并接收连接就好了;只有客户端崩溃。造成这种情况的原因是什么?

    编辑:我让客户端使用以下代码:

    import pickle
    import socket
    import threading
    
    class ConnectionThread(threading.Thread):
        def run(self):
            for x in range(10):
                client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                client.connect(('localhost', 2727))
                client.send(pickle.dumps(x))
                print('Sent:',str(x))
                print('Received:',repr(pickle.loads(client.recv(1024))))
                client.close()
    
    for x in range(5):
        ConnectionThread().start()
    

    然而,我仍然不明白发生了什么。这不仅仅是打开和关闭套接字多次?不应该有时间限制(关闭后不应该这么快就打开一个套接字)?

2 个答案:

答案 0 :(得分:10)

您的客户端现在正确 - 您要打开套接字发送数据,接收回复然后关闭套接字。

错误原始错误是由服务器在发送第一个响应后关闭套接字引起的,该响应导致客户端在尝试在同一连接上发送第二条消息时收到连接已关闭的消息。

  

但是,我还是不明白   这是怎么回事。不是这个   打开和关闭插座一堆   时间?

是。如果不是最高性能的做事方式,这是可以接受的。

  

不应该有时间   限制(你不应该   这么快就能打开一个插座   关闭它?)

您可以随意打开客户端套接字,因为每次打开套接字时都会获得一个新的本地端口号,这意味着连接不会干扰。在上面的服务器代码中,它将为每个传入连接启动一个新线程。

每个IP连接有4个部分(source_address,source_port,destination_address,destination_port),这个四边形(因为它已知)必须改变以进行永久连接。除了source_port之外的所有内容都是针对客户端套接字修复的,这就是操作系统为您所做的更改。

打开服务器套接字更麻烦 - 如果您想快速打开新的服务器套接字,那么

server.bind(('', 2727))

然后你需要阅读SO_REUSEADDR。

答案 1 :(得分:-20)

  1. 套接字太低级,Python是一种高级语言。然后,以pythonic方式进行Python网络编程,你想避免完全处理套接字,并将其留给某个模块或包。如果你想了解低级别的东西是如何工作的,那么研究现有的实现是必不可少的,所以学习high-level library是必不可少的。
  2. pickle并不是你如何序​​列化Python对象以便将它们发送到网上。它们是一个潜在的安全问题,因为你可以制作一个假的腌制数据包,在打开时执行arbritary代码。最好使用安全的序列化方法 - 因为有很多可用的方法,比如在整数对象上调用str(),在另一侧调用int()
  3. 要同时提供/收听多个客户端,请勿使用线程。特别是,永远不要使用您似乎正在使用的“每个连接一个线程”方法。它不像你想象的那样扩展。由于使用线程也容易出错并且难以调试,并且对最终结果bringing problems instead完全没有优势,所以只是试图完全避免它们。套接字(以及第1项中讨论的higher level libraries)可以在非阻塞模式下工作,您可以在其他代码运行时进行操作,并且可以完成而不使用线程
  4. 我刚刚看到你对这个问题的评论:

      

    @leeroy(续)我的目标是努力实现这样的事情:http://www.mcwalter.org/technology/java/httpd/tiny/index.html只在Python中

    嗯,这是一个有效的实施方案:

    from SimpleHTTPServer import SimpleHTTPRequestHandler as RH
    from SocketServer import TCPServer
    
    print "serving current directory at port 8000"
    TCPServer(("", 8000), RH).serve_forever()