【问题标题】:Using Python in Windows, how do I send and retrieve an arbitrary amount of data over a socket connection?在 Windows 中使用 Python,如何通过套接字连接发送和检索任意数量的数据?
【发布时间】:2011-10-22 22:45:15
【问题描述】:

我正在尝试遵循 online tutorial 中关于使用标准 Python 库(版本 2.7)进行基本客户端-服务器套接字编程的示例,但我无法让该示例在 Windows(Vista)下工作。它在 Ubuntu 11.10 中运行良好,所以我知道下面的代码至少可以在基于 UNIX 的环境中运行:

import optparse, os, socket, time

def parse_args():
    parser = optparse.OptionParser(usage)

    help = "The port to listen on. Default to a random available port."
    parser.add_option('--port', type='int', help=help)

    help = "The interface to listen on. Default is localhost."
    parser.add_option('--iface', help=help, default='localhost')

    help = "The number of seconds between sending bytes."
    parser.add_option('--delay', type='float', help=help, default=.1)

    help = "The number of bytes to send at a time."
    parser.add_option('--num-bytes', type='int', help=help, default=10)

    options, args = parser.parse_args()
    if len(args) != 1:
        parser.error('Provide exactly one poetry file.')   
    poetry_file = args[0]
    if not os.path.exists(args[0]):
        parser.error('No such file: %s' % poetry_file)
    return options, poetry_file


def send_poetry(sock, poetry_file, num_bytes, delay):
    inputf = open(poetry_file)
    while True:
        bytes = inputf.read(num_bytes)
        if not bytes:
            sock.close()
            inputf.close()
            return

        print 'Sending %d bytes' % len(bytes)

        try:
            sock.sendall(bytes) # this is a blocking call
        except socket.error:
            sock.close()
            inputf.close()
            return

        time.sleep(delay)


def serve(listen_socket, poetry_file, num_bytes, delay):
    while True:
        sock, addr = listen_socket.accept()
        print 'Somebody at %s wants poetry!' % (addr,)
        send_poetry(sock, poetry_file, num_bytes, delay)


def main():
    options, poetry_file = parse_args()
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind((options.iface, options.port or 0))
    sock.listen(5)
    print 'Serving %s on port %s.' % (poetry_file, sock.getsockname()[1])
    serve(sock, poetry_file, options.num_bytes, options.delay)


if __name__ == '__main__':
    main()



一旦套接字在serve() 函数中调用accept(),程序就会停止响应,据我所知,没有收到任何请求的数据。关于 Windows 对套接字的处理,我忽略了什么?

【问题讨论】:

  • 你怎么知道程序在“接受”时停止响应?你看到“有人想要诗歌”的信息了吗?
  • 因为我在从未到达的语句之后设置了一个断点。所以不,我没有看到“有人想要诗歌”的消息。
  • 如果您卡在“接受”上,则说明没有人连接到您的套接字。尝试 telnet 连接到端口。下面的答案也有很好的信息。
  • 是的,看起来客户端没有连接到套接字端点。我认为这与 Windows 不允许重用 localhost 接口有关(这是我正在关注的教程的作者有意介绍的一个功能) - 但我还没有找到解决方法.

标签: python sockets networking client-server winsock


【解决方案1】:

看起来您可能需要让它在 2 个不同的进程中运行,或者将客户端和服务器分成 2 个不同的线程。我刚刚让它在我的 Win7 机器上工作:

client.py

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("localhost", 4242))
while True:
    line = input("String to send: ")
    s.send(line.encode("utf-8"))

server.py:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("0.0.0.0", 0))
s.listen(5)
client, address = s.accept()
while 1:
    data = client.recv(1024)
    if data:
        client.send(data)
        print(data.decode("utf-8"))

结果:

C:\Users\jon\Desktop>python.exe client.py
要发送的字符串:“你好!”

独立控制台

C:\Users\jon\Desktop>python server.py
你好!

更多关于Winsock Programmer’s FAQ的好信息


您使用的脚本挂在sock, addr = listen_socket.accept()(如果设置为sock.settimeout(x),则直到超时)。如果使用sock.setblocking(0),则会在accept() 行抛出异常socket.error: [Errno 10035] A non-blocking socket operation could not be completed immediately,这就是超时所发生的情况:

def serve(listen_socket, poetry_file, num_bytes, delay):
    while True:
        print "accepting data"
        try:
            sock, addr = listen_socket.accept()
        except socket.error, e:
            print e
        else:
            print 'Somebody at %s wants poetry!' % (addr,)
            send_poetry(sock, poetry_file, num_bytes, delay)


def main():
    options, poetry_file = parse_args()
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.bind((options.iface, options.port or 0))
    sock.listen(5)
    sock.settimeout(5)
    print 'Serving %s on port %s.' % (poetry_file, sock.getsockname()[1])
    serve(sock, poetry_file, options.num_bytes, options.delay)


if __name__ == '__main__':
    main()

结果:

C:\Users\jon\Desktop>python.exe test.py poetry.txt                                              
Serving poetry.txt on port 25355.                                                                   
accepting data                                                                                      
timed out                                                                                           
accepting data                                                                                      
timed out                                                                                           
accepting data                                                                                      
timed out                                                                                           
accepting data                                                                                      
timed out                                                                                           
accepting data                                                                                      
timed out                                                                                           
accepting data                                                                                      
timed out                                                                                           
accepting data                                                                                      
timed out                                                                                           
accepting data  

【讨论】:

  • 首先,感谢您为我解决了所有这些问题。但是,我真的很想知道为什么我的代码不能在 Windows 中运行,因为我相信它与将来可能会再次出现的重要事物有关。经过更多研究,我相信问题与我正在使用的SO_REUSEADDR 选项有关。此选项 [应该] 允许客户端和服务器都在 localhost 接口上运行而没有任何问题,但事实并非如此。
  • 理论上是正确的。但是从我读过的内容和运行一些测试来看,它有时似乎有效,但有时无效。我还读到重新启动你的电脑实际上可以让它工作一段时间,但它最终会像我们的测试一样无限期地挂起。更多好信息在这里:itamarst.org/writings/win32sockets.html
  • 嘿,我今天早些时候发现了那篇文章。这家伙基本上说(在经过广泛研究之后)Windows 中发生了奇怪的、不一致的事情,这就是它的方式(也许它是)。
猜你喜欢
  • 1970-01-01
  • 2012-02-12
  • 2010-12-10
  • 2021-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-13
相关资源
最近更新 更多