为什么这个Python UDP套接字会被重置为'None'?

1 投票
3 回答
1143 浏览
提问于 2025-04-29 00:46

我写了一些Python代码,创建了一个叫做UDPServer的类,这个类里面有一个UDP套接字。在构造函数里,我初始化了这个套接字,并把它绑定到本地地址和一个特定的端口。这个步骤报告说成功了。然后我有一个单独的成员函数,用来监听这个套接字上是否有数据进来。但是它报告说这个套接字是'None'。我的问题是为什么会这样?如果我把套接字的初始化从构造函数中移到监听函数里(也就是说初始化和监听都放在一个函数里),那么套接字就不会变成'None',我也能接收到数据。

代码如下:

import socket

class UDPServer:
    def __init__(self, dst_ip, rcv_port, snd_port):
        self._dstip = dst_ip
        self._rcv_port = rcv_port
        self._snd_port = snd_port
        self._sock = self._create_socket()

    def _create_socket(self):

        # Create Datagram (udp) socket
        try :
            self._sock = socket.socket(socket.AF_INET, # Internet
                                       socket.SOCK_DGRAM) # UDP
            print 'Socket created.'
        except socket.error, msg :
            print 'Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
            sys.exit()

        # Bind socket to local host and port
        try:
            self._sock.bind(("", self._rcv_port))
        except socket.error , msg:
            print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
            sys.exit()

        if(self._sock == None):
            print "self._sock is None after bind!!"

        print 'Socket bind complete.'

    def _receive_msg(self):     
        print "waiting on port:", self._rcv_port
        while True:
            if(self._sock == None):
                print "self._sock is None!"
            data, addr = self._sock.recvfrom(1024) # buffer size is 1024 bytes
            print "received message:", data     

def main():
    DST_IP = "100.1.11.275"
    UDP_RCV_PORT = 30001
    UDP_SND_PORT = 30002

    # Create UDP Server
    udpServer = UDPServer(DST_IP, UDP_RCV_PORT, UDP_SND_PORT)
    udpServer._receive_msg()

if __name__ == "__main__":
    main()

输出结果如下(我是在Windows的命令提示符下运行的):

d:\python_tests>python udp_server.py
Socket created.
Socket bind complete.
waiting on port: 30001
self._sock is None!
Traceback (most recent call last):
  File "udp_server.py", line 51, in <module>
    main()
  File "udp_server.py", line 48, in main
    udpServer._receive_msg()
  File "udp_server.py", line 38, in _receive_msg
    data, addr = self._sock.recvfrom(1024) # buffer size is 1024 bytes
AttributeError: 'NoneType' object has no attribute 'recvfrom'

d:\python_tests>
暂无标签

3 个回答

1

_create_socket(self) 这个函数并没有返回新创建的套接字,实际上这个函数并没有明确返回任何值。在Python中,如果一个函数没有遇到明确的返回语句,它会默认返回 None。在你的情况中,这意味着 self._create_socket() 返回的是 None,而这个 None 被赋值给了 self._sock,这就覆盖了在 self._create_socket() 中设置的值。

所以,在 __init__() 方法中,只需要调用 self._create_socket(),而不需要把返回值赋给 self._sock

class UDPServer:
    def __init__(self, dst_ip, rcv_port, snd_port):
        self._dstip = dst_ip
        self._rcv_port = rcv_port
        self._snd_port = snd_port
        self._create_socket()
2

_create_socket 这个方法里,创建一个套接字:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

然后返回这个套接字,这样在 __init__ 方法里,self._sock 就能得到实际的套接字。现在的情况是,self._sock 被赋值为 None,因为如果函数没有返回其他值,默认返回的就是 None

举个例子:

def _create_socket(self):

        # Create Datagram (udp) socket
        try :
            sock = socket.socket(socket.AF_INET, # Internet
                                 socket.SOCK_DGRAM) # UDP
            print 'Socket created.'
        except socket.error, msg :
            print 'Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
            sys.exit()

        # Bind socket to local host and port
        try:
            sock.bind(("", self._rcv_port))
        except socket.error , msg:
            print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
            sys.exit()

        if sock == None:
            print "sock is None after bind!!"

        print 'Socket bind complete.'

        return sock ### try this

另外一种方法: 一开始就不要写 self._sock = self._create_socket,这样你的代码就能正常工作了。

1

在构造函数里,你把 self._sock 赋值为 self._create_socket() 的返回值。问题是,self._create_socket() 并没有返回任何东西,或者说它返回的是默认值 None

如果你直接在函数里修改 self._sock,或者让它返回,就可以正常工作了:

import socket

class UDPServer:
    def __init__(self, dst_ip, rcv_port, snd_port):
        self._dstip = dst_ip
        self._rcv_port = rcv_port
        self._snd_port = snd_port
        self._create_socket()

    def _create_socket(self):

        # Create Datagram (udp) socket
        try :
            self._sock = socket.socket(socket.AF_INET, # Internet
                                       socket.SOCK_DGRAM) # UDP
            print 'Socket created.'
        except socket.error, msg :
            print 'Failed to create socket. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
            sys.exit()

        # Bind socket to local host and port
        try:
            self._sock.bind(("", self._rcv_port))
        except socket.error , msg:
            print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
            sys.exit()

        if(self._sock == None):
            print "self._sock is None after bind!!"
        print 'Socket bind complete.'

    def _receive_msg(self):     
        print "waiting on port:", self._rcv_port
        while True:
            if not self._sock:
                print "self._sock is None!"
            data, addr = self._sock.recvfrom(1024) # buffer size is 1024 bytes
            print "received message:", data     

def main():
    DST_IP = "100.1.11.275"
    UDP_RCV_PORT = 30001
    UDP_SND_PORT = 30002

    # Create UDP Server
    udpServer = UDPServer(DST_IP, UDP_RCV_PORT, UDP_SND_PORT)
    udpServer._receive_msg()

if __name__ == "__main__":
    main()

撰写回答