NSIS中的窗口套接字编程
答
!include LogicLib.nsh
!ifndef AF_INET
!define AF_INET 2
!define SOCK_STREAM 1
!define IPPROTO_TCP 6
!define INADDR_ANY 0
!define SOL_SOCKET 0xffff
!define /math SO_EXCLUSIVEADDRUSE 0xffffffff^0x4
!endif
Function QueryCanBindToIP4TCPPort
Exch $0
Push $1
Push $2
Push $0 ;Push port
System::Alloc 16 ;WSADATA & sockaddr_in
System::Call 'Ws2_32::WSAStartup(i 2,isr2)i.r0'
${If} $0 = 0
System::Call 'Ws2_32::socket(i ${AF_INET},i ${SOCK_STREAM},i ${IPPROTO_TCP})i.r1 ?e'
Pop $0
${If} $1 <> -1
System::Call 'Ws2_32::setsockopt(ir1,i ${SOL_SOCKET},i ${SO_EXCLUSIVEADDRUSE},*i 1,i4)i.r0'
System::Call 'Ws2_32::htons(iss)i.s' ;Convert port (and leaves the original push on the stack)
;Skipping htonl on address since INADDR_ANY is 0
System::Call '*$2(&i2 ${AF_INET},&i2 s,&i4 ${INADDR_ANY},&i8 0)'
System::Call 'Ws2_32::bind(ir1,ir2,i16)i.r0'
${If} $0 = 0
System::Call 'Ws2_32::listen(ir1,i0)i.r0'
;Listening here but once we hit WSACleanup the port will be free again (This is fine if all you need to do is make sure no app is bound to the port at this moment)
; System::Call 'Ws2_32::closesocket(ir1)'
${EndIf}
${EndIf}
System::Call 'Ws2_32::WSACleanup()' ;Remove this call to leave the port open for the duration of the installer
${EndIf}
System::Free $2
Pop $2 ;Throw away port
Pop $2
Pop $1
Exch $0
FunctionEnd
Section
Push 666
call QueryCanBindToIP4TCPPort
Pop $0
${If} $0 = 0
DetailPrint "Bind OK"
${Else}
DetailPrint "Bind Failed!"
${EndIf}
SectionEnd
答
由于NSIS没有任何网络功能是内置的或者我能找到任何插件,在我看来,最简单的解决方案是让试图创建一个很小的程序监听指定端口上的套接字(端口可以是硬编码或作为参数传递)。然后可以在安装脚本中使用该程序来检查端口是否可用。
如果我尝试使用相同的端口不止一次调用此函数QueryCanBindToIP4TCPPort,然后安装将中止:( – user1234 2012-01-20 08:10:38
为什么你会检查相同的端口不止一次?尝试取消注释closesocket调用 – Anders 2012-01-20 08:42:24
'$ {If} $ 0 = 0'这可以检查$ 0的值,或者我们必须使用这个'$ {If} $ 0 == 0' – user1234 2012-01-20 08:58:25