Как использовать Windows API ‘GetTcpTable’ для поиска доступного tcp-порта?

#openedge #progress-4gl

#openedge #прогресс -4gl

Вопрос:

Я пытаюсь использовать Windows api ‘GetTcpTable’, но я не знаю, как подготовить структуру данных ‘PMIB_TCPTABLE’ и получить из нее возвращаемое значение.

 PROCEDURE GetTcpTable EXTERNAL "Iphlpapi":U:
   DEFINE OUTPUT        PARAMETER mTcpTable              AS HANDLE TO MEMPTR. // the API expects a pointer, so use HANDLE TO syntax to pass one
   DEFINE INPUT-OUTPUT  PARAMETER SizePointer            AS HANDLE TO LONG.
   DEFINE INPUT         PARAMETER Order                  AS LONG.
   DEFINE RETURN        PARAMETER IPHLPAPI_DLL_LINKAGE   AS LONG.
END PROCEDURE.
 
DEFINE VARIABLE mTcpTable        AS MEMPTR   NO-UNDO.
DEFINE VARIABLE SizePointer      AS INT      NO-UNDO.
DEFINE VARIABLE Order            AS INT      NO-UNDO.
DEFINE VARIABLE IPHLPAPI         AS INT      NO-UNDO.
 
DEFINE VARIABLE mTempValue       AS MEMPTR   NO-UNDO.
DEFINE VARIABLE dwNumEntries     AS INT      NO-UNDO.
DEFINE VARIABLE dwState          AS INT      NO-UNDO.
DEFINE VARIABLE dwLocalAddr      AS INT64    NO-UNDO.
DEFINE VARIABLE dwLocalPort      AS INT      NO-UNDO.
DEFINE VARIABLE dwRemoteAddr     AS INT64    NO-UNDO.
DEFINE VARIABLE dwRemotePort     AS INT      NO-UNDO.
 
DEFINE VARIABLE ix     AS INTEGER NO-UNDO.
 
SizePointer = 4.
Order = 1.
SET-SIZE(mTcpTable) = SizePointer.
RUN GetTcpTable(OUTPUT mTcpTable, INPUT-OUTPUT SizePointer,INPUT Order, OUTPUT IPHLPAPI). //get ERROR_INSUFFICIENT_BUFFER and know the real buffer now
 
MESSAGE "IPHLPAPI is " IPHLPAPI SKIP // ERROR_INSUFFICIENT_BUFFER = 122
        "SizePointer is " SizePointer SKIP
   VIEW-AS ALERT-BOX.
 
SET-SIZE(mTcpTable) = 0.
SET-SIZE(mTcpTable) = SizePointer.
RUN GetTcpTable(OUTPUT mTcpTable, INPUT-OUTPUT SizePointer,INPUT Order, OUTPUT IPHLPAPI). 
 
MESSAGE "IPHLPAPI is " IPHLPAPI SKIP  // NO_ERROR = 0
        "SizePointer is " SizePointer SKIP
        GET-LONG(mTcpTable,1) SKIP //dwNumEntries
   VIEW-AS ALERT-BOX.
 
IF IPHLPAPI = 0 THEN DO:
   dwNumEntries = GET-LONG(mTcpTable,1).
 
   OUTPUT TO VALUE ("C:tempdebug.txt") UNBUFFERED.
   DO ix = 0 TO dwNumEntries - 1.
      dwState                 = GET-UNSIGNED-LONG(mTcpTable,5   ix * 20). // get value of dwState
      dwLocalAddr             = GET-UNSIGNED-LONG(mTcpTable,9   ix * 20). // get value of dwLocalAddr
 
      SET-SIZE(mTempValue)    = 2.
      PUT-BYTE(mTempValue,2)  = GET-UNSIGNED-SHORT(mTcpTable,13   ix * 20).
      PUT-BYTE(mTempValue,1)  = GET-UNSIGNED-SHORT(mTcpTable,14   ix * 20).
      dwLocalPort             = GET-UNSIGNED-SHORT(mTempValue,1). // get value of dwLocalPort, The maximum size of an IP port number is 16 bits, so only the lower 16 bits should be used. The upper 16 bits may contain uninitialized data.
      SET-SIZE(mTempValue)    = 0.
 
      dwRemoteAddr            = GET-UNSIGNED-LONG(mTcpTable,17   ix * 20). // get value of dwRemoteAddr
 
      SET-SIZE(mTempValue)    = 2.
      PUT-BYTE(mTempValue,2)  = GET-UNSIGNED-SHORT(mTcpTable,21   ix * 20).
      PUT-BYTE(mTempValue,1)  = GET-UNSIGNED-SHORT(mTcpTable,22   ix * 20).
      dwRemotePort            = GET-UNSIGNED-SHORT(mTempValue,1). // get value of dwRemotePort, The maximum size of an IP port number is 16 bits, so only the lower 16 bits should be used. The upper 16 bits may contain uninitialized data.
      SET-SIZE(mTempValue)    = 0.
 
      PUT UNFORMATTED dwState "~t" dwLocalAddr "~t" dwLocalPort "~t" dwRemoteAddr "~t" dwRemotePort "~r".
   END.
   OUTPUT CLOSE.
END.
 
SET-SIZE(mTcpTable) = 0.
  
  • Есть ли лучший способ получить младшие 16 бит? Я не уверен, зачем мне нужно помещать байт в обратном порядке в mTempValue, привязан ли он к небольшому конечному разряду ПК x86?
  • Как получить правильную начальную позицию для чтения значения, если я запускаю код на другом компьютере с разрядностью

Я думаю, что теперь вопрос можно закрыть:
https://community.progress.com/s/feed/0D54Q000088eIeASAU?t=1602495359075amp;searchQuery
Спасибо, ребята 🙂

Комментарии:

1. Вы говорите, что сейчас пытаетесь использовать GetTcpTable. Но ваш код, похоже, этого не показывает. Вы должны опубликовать код, с которым у вас действительно возникла проблема.

2. Какая строка вашего . Чистый пример выдает вашу ошибку? На 11.6 и 12.2 (оба x64) в Windows 10 я получаю либо порт, когда порт свободен, либо порт 1, если порт используется.

3. @TomBascom Спасибо! Да, вы правы, я должен это сделать, но я понятия не имел о подготовке структуры данных, когда задавал вопрос, поэтому я не вставлял свой код. Теперь я получил ответ от сообщества progress. Кстати: Я впервые задаю вопрос о переполнении стека, что мне делать дальше? Должен ли я вставить ответ на этот вопрос или просто закрыть его?

4. Вы должны, по крайней мере, поддержать nwahmaet, поскольку вы отметили, что его ответ заслуживает «Спасибо». Помимо этого, я бы подумал, что разъяснение исходного вопроса, отражающего то, о чем вы на самом деле спрашивали, вместо того, чтобы показывать код, который связан только косвенно, безусловно, было бы хорошей идеей. Лично я бы предложил тому, кто ответил на ваш вопрос в сообществе progress, также опубликовать этот ответ здесь, чтобы вы могли проголосовать за него и пометить его правильно.

5. @TomBascom многие ценят ваши предложения, я уже отредактировал свой вопрос и уточнил, о чем на самом деле вопрос, о котором я спрашиваю 🙂

Ответ №1:

В документе Microsoft обычно содержатся определения структур (см. https://learn.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcptable ). Как только вы узнаете их — и любые другие, связанные / указывающие на / etc — вы можете создавать и управлять ими, используя MEMPTR типы данных и различные функции, которые работают с ними: SET-SIZE() , GET-BYTES() и GET-POINTER-VALUE() обычно используются. Об этом есть документ по адресу https://docs.progress.com/bundle/openedge-programmimg-interfaces/page/Shared-Library-and-DLL-Support.html .

Комментарии:

1. Привет, спасибо, теперь я могу получить информацию из возвращаемого значения. Но моя начальная позиция таблицы MIB_TCPROW [ANY_SIZE] является 5-м байтом mTcpTable, похоже, что значение байтов в mTcpTable следует в следующем порядке: dwNumberEntries, таблица MIB_TCPROW [1], таблица MIB_TCPROW [1] … правильно ли это? Извините, я не знаю, как вставить код из-за ограничения символов комментариев