Проблемный участок кода выглядит примерно так:
import socket, my_custom_socket_address_getting_module
underlyingSocketFileno = my_custom_socket_address_getting_module.get()
connectedSocket = socket.socket( fileno=underlyingSocketFileno )
clientAddress = connectedSocket.getpeername()
Где «my_custom_socket_address_getting_module» - это настраиваемое расширение C, которое возвращает адрес открытого сокета на моей машине (как длинный).
Первые две строки работают хорошо, а объект сокета Python выглядит разумным (например, fd и другие свойства сокета выглядят правильно в отладчике), но попытка вызвать getpeername для объекта вызывает следующее исключение:
<class 'OSError'>:[WinError 10014] The system detected an invalid pointer address in attempting to use a pointer argument in a call
Поскольку я позволяю Python создавать как сокет Python (и, предположительно, так и поддерживающую ОС SOCKET), я понятия не имею, откуда взялся адрес сломанного указателя.
Я вполне уверен, что адрес сокета, передаваемый Python из моего настраиваемого модуля, правильный, и что адрес сокета, который он возвращает, действителен, поскольку расширение отлично работало с моей старой версией Python.
Эта проблема возникла, когда я перешел на гораздо более новую версию Python (3.6.5) - есть ли идеи относительно того, почему эта новая версия будет вести себя так? Предыдущая рабочая версия была Python 1.5.2 (да, действительно).
(ОС - Microsoft Windows 8.1 64, Python 3.6.5, построенная с MSVCC v.1911)
Вы также должны указать, какую версию вы использовали ранее.
@pts Я согласен с тем, что мне придется поступить именно так, если я не найду больше многообещающих потенциальных клиентов. К сожалению, предыдущей рабочей версией был Python 1.5.2, так что здесь есть над чем поработать.
Я бы попробовал 2.0.1 (python.org/download/releases/2.0.1), затем 2.7.14 (python.org/downloads/release/python-2714). Если работает только 2.0.1, то можно разделить пополам: попробуйте последнюю версию 2.4 и т. д.
Если вам не повезло, что пользователь StackOverflow или пользователь списка рассылки Python не знают ответа, возможно, вам придется проделать утомительную работу, попробовав несколько версий Python.
Что означает «возвращает адрес сокета открытого сокета», какой тип C возвращаемого значения?
Возможно, вы перешли с 32-битного Python (1.5.2) на 64-битный Python (3.6.5)?
Вы пробовали сбросить winsock? netsh winsock reset в терминале
Какое семейство и тип розетки?
Предполагая, что IPv6 включен в ОС, я бы проверил, был ли Python собран с поддержкой IPv6, проверив socket.has_ipv6. Если нет, то Python отправляет IPv6-адрес в sock_addr, который слишком мал (sock_addr_storage больше и будет подходящим). Python 1.5.2 работает, потому что буфер определен как char addrbuf[256], в котором достаточно места для получения адреса IPv6.






Из Документы Python 3 для конструктора socket.socket:
If fileno is specified, the other arguments are ignored, causing the socket with the specified file descriptor to return.
Возможно, это было очевидно для автора документации, но похоже, что это работает, только если сокет, связанный с передаваемым вами fileno, был создан Python. Если вы пытаетесь подключиться к сокету, который был открыт модулем расширения, Python создаст объект socket с предоставленным вами fileno, но для других свойств сокета (тип, семейство, протокол) будут установлены значения по умолчанию. .
В этом случае сокет был сокетом IPv6, но по умолчанию для сокетов Python используется IPv4. Указание типа и семейства сокета вручную устранило проблему.
«другие свойства сокета (тип, семейство, протокол) будут установлены в значения по умолчанию»: это было изменено в Python 3.7 github.com/python/cpython/blob/…
Бенджамин, не могли бы вы рассказать, как вы это обнаружили? Сам по себе ответ действительно крутой, но читатели также могут извлечь уроки из вашей цепочки гипотез и проверок.
@void: Бен обнаружил проблему, изучив исходный код Python для создания сокета. (Я работаю с Беном; я не экстрасенс. :-)
Какая старая версия Python работала? Пожалуйста, добавьте это в ошибку. Чтобы отладить проблему, вы можете попробовать ее со всеми промежуточными версиями Python, и когда вы выясните, какая версия сломала ее, спросите, в частности, в списке рассылки Python, чтобы поговорить с разработчиками.