【问题标题】:Server crashes when the client is closing客户端关闭时服务器崩溃
【发布时间】:2013-09-12 14:33:20
【问题描述】:

我今天早些时候遇到了这个问题。这是我的第一个网络应用程序。

server.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

s = socket.socket()
host = socket.gethostname()

# Reserve a port for your service.
port = 12345
# Bind to the port
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host, port))

# Now wait for client connection.
s.listen(1)
conn, addr = s.accept()
try:
    while True:
        # connection, address
        content = conn.recv(1024)
        if content in ('status', 'stop', 'start', 'reload', 'restart'):
            conn.send('%s received' % content)
        else:
            conn.send('Invalid command')
except KeyboardInterrupt:
    conn.close()
    s.shutdown(socket.SHUT_RDWR)
    s.close()

client.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

import socket

s = socket.socket()
host = socket.gethostname()
port = 12345

s.connect((host, port))
try:
    while True:
        print ''
        value = raw_input('Enter a command:\n')
        if value != '':
            s.send(value)
            print s.recv(1024)
except KeyboardInterrupt:
    s.shutdown(socket.SHUT_RDWR)
    s.close()

这是一个非常基本的客户端/服务器应用程序。服务器启动,等待 客户端发送命令。客户端连接到服务器,要求用户 键入命令。然后将命令发送到回复<command> receivedInvalid command 的服务器。 代码运行良好,直到我点击CTRL+C。服务器崩溃了。这是为什么呢?

例子:

python client.py 

Enter a command:
stop
stop received

Enter a command:
status
status received

Enter a command:
bla
Invalid command

Enter a command:
^C

在服务器端:

python server.py 
Traceback (most recent call last):
  File "server.py", line 25, in <module>
    conn.send('Invalid command')
socket.error: [Errno 32] Broken pipe

【问题讨论】:

  • 您知道socket.send 不能保证将您传递给它的整个字符串都发送给它吗?
  • 因为我只读取 1024 个字节?如果是这样,是的,我知道,但我只阅读几个字符,所以这并不重要
  • 如果你不关心你的应用程序是否可靠也没关系。 :) 许多路由器可以并将 1024 字节(或更少)的 TCP 流量分割成多个 IP 数据报。另外还有另一个错误,那就是您的协议没有框架:没有什么可以阻止您的服务器由于单次读取而意外获得“statusstop”。您可能想阅读xml.com/pub/au/215 以了解更多信息!

标签: python sockets networking client-server


【解决方案1】:

也将您的accept 放入一个while 循环中。比如:

while True:
    conn, addr = s.accept()        # accept one connection.
    while True:                    # Receive until client closes.
        content = conn.recv(1024)  # waits to receive something.
        if not content:            # Receive nothing? client closed connection,
            break                  #   so exit loop to close connection.
        if content in ('status', 'stop', 'start', 'reload', 'restart'):
            conn.send('%s received' % content)
        else:
            conn.send('Invalid command')
    conn.close()                   # close the connection 

还要注意recv在客户端关闭连接时返回空字符串,因此if not content: break

【讨论】:

  • 为什么这比try/except 声明更好?你可以说得更详细点吗?否则,谢谢你的回答
  • 更流畅的代码流。非重复(在两个地方接受)。更明确的意图。建立连接,接收数据直到客户端关闭,关闭连接并重复。
  • 我没有得到的部分是:如果内容是'',那么这意味着客户端关闭了连接。谢谢
  • 阅读socket.recv 文档。对于同步连接,recv 将等待至少一个字节的数据准备好,但如果客户端关闭连接,将返回零字节(一个空字符串)。
  • 非常感谢,这对我帮助很大
【解决方案2】:

基本上,我并没有在我的服务器上为新的未来客户重新创建新连接,然后,当它到达conn.send('Invalid command') 时,它就崩溃了。要解决这个问题:

我刚换了:

conn.send('Invalid command')

与:

try:
    conn.send('Invalid command')
except socket.error:
    conn, addr = s.accept()

【讨论】:

    猜你喜欢
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多