找回密码
 加入
搜索
查看: 10091|回复: 18

[网络通信] 创建TCP连接时,系统自动分配的端口,怎么样获取这个端口呢

 火.. [复制链接]
发表于 2010-7-30 08:22:37 | 显示全部楼层 |阅读模式
本帖最后由 破帽遮颜 于 2010-8-1 14:56 编辑

创建TCP连接,端口号为0时,系统会自动分配一个空闲端口,使用什么方法可以获取这个端口号呢?

getsockname?

悬赏贴http://www.autoitx.com/thread-17303-1-1.html
#include 'array.au3'

TCPStartup()
Global Const $__TCP_WINDOW = GUICreate('')
Global $hWs2_32 = -1


_TCP_Server_Create(0, '0.0.0.0')
MsgBox(4096, '', '现在服务端创建的TCP连接使用的端口是?该如何获取呢?')

While 1
        Sleep(100)
WEnd


Func _TCP_Server_Create($iPort, $sIP = "0.0.0.0")
        $hListenSocket = _ASocket()
        _ASockSelect($hListenSocket, $__TCP_WINDOW, 0x0400, 8)
        _ASockListen($hListenSocket, $sIP, $iPort)
        Return $hListenSocket
EndFunc   ;==>_TCP_Server_Create

Func _ASocket($iAddressFamily = 2, $iType = 1, $iProtocol = 6)
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        Local $hSocket = DllCall($hWs2_32, "uint", "socket", "int", $iAddressFamily, "int", $iType, "int", $iProtocol)
        If @error Then
                SetError(1, @error)
                Return -1
        EndIf
        If $hSocket[0] = -1 Then
                SetError(2, _WSAGetLastError())
                Return -1
        EndIf
        Return $hSocket[0]
EndFunc   ;==>_ASocket

Func _ASockSelect($hSocket, $hWnd, $uiMsg, $iEvent)
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        Local $iRet = DllCall($hWs2_32, "int", "WSAAsyncSelect", "uint", $hSocket, "hwnd", $hWnd, "uint", $uiMsg, "int", $iEvent)
        If @error Then
                SetError(1, @error)
                Return False
        EndIf
        Return True
EndFunc   ;==>_ASockSelect

Func _ASockListen($hSocket, $sIP, $uiPort, $iMaxPending = 5)
        Local $iRet
        Local $stAddress
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        $stAddress = __SockAddr($sIP, $uiPort)
        If @error Then
                SetError(@error, @extended)
                Return False
        EndIf

        $iRet = DllCall($hWs2_32, "int", "bind", "uint", $hSocket, "ptr", DllStructGetPtr($stAddress), "int", DllStructGetSize($stAddress))
        If @error Then
                SetError(3, @error)
                Return False
        EndIf
        If $iRet[0] <> 0 Then
                $stAddress = 0
                SetError(4, _WSAGetLastError())
                Return False
        EndIf

        $iRet = DllCall($hWs2_32, "int", "listen", "uint", $hSocket, "int", $iMaxPending)
        If @error Then
                SetError(5, @error)
                Return False
        EndIf
        If $iRet[0] <> 0 Then
                $stAddress = 0
                SetError(6, _WSAGetLastError())
                Return False
        EndIf
        Return True
EndFunc   ;==>_ASockListen

Func __SockAddr($sIP, $iPort, $iAddressFamily = 2)
        Local $iRet
        Local $stAddress
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        $stAddress = DllStructCreate("short;ushort;uint;char[8]")
        If @error Then
                SetError(1, @error)
                Return False
        EndIf
        DllStructSetData($stAddress, 1, $iAddressFamily)
        $iRet = DllCall($hWs2_32, "ushort", "htons", "ushort", $iPort)
        DllStructSetData($stAddress, 2, $iRet[0])
        $iRet = DllCall($hWs2_32, "uint", "inet_addr", "str", $sIP)
        If $iRet[0] = 0xffffffff Then
                $stAddress = 0
                SetError(2, _WSAGetLastError())
                Return False
        EndIf
        DllStructSetData($stAddress, 3, $iRet[0])
        Return $stAddress
EndFunc   ;==>__SockAddr

Func _WSAGetLastError()
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        Local $iRet = DllCall($hWs2_32, "int", "WSAGetLastError")
        If @error Then
                ConsoleWrite("+> _WSAGetLastError(): WSAGetLastError() failed. Script line number: " & @ScriptLineNumber & @CRLF)
                SetExtended(1)
                Return 0
        EndIf
        Return $iRet[0]
EndFunc   ;==>_WSAGetLastError
 楼主| 发表于 2010-7-30 08:24:38 | 显示全部楼层
希望有高手指点
 楼主| 发表于 2010-7-30 19:57:43 | 显示全部楼层
Up~~~~~~~~~~~~~~~~~~~~~
发表于 2010-7-30 23:16:30 | 显示全部楼层
能指定端口吗,
我试过UDP发送数据,可以指定远程的端口号,但不能指定本地发送数据的端口号
 楼主| 发表于 2010-7-31 00:40:45 | 显示全部楼层
能指定端口吗,
我试过UDP发送数据,可以指定远程的端口号,但不能指定本地发送数据的端口号
auto 发表于 2010-7-30 23:16


指定端口就失去这个问题的意义了。
呵呵
发表于 2010-7-31 03:00:48 | 显示全部楼层
先具体解释下端口为0是怎样?
你所说的TCP连接是指
TCPListen
?
TCPConnect
?
or???
 楼主| 发表于 2010-7-31 08:46:48 | 显示全部楼层
本帖最后由 破帽遮颜 于 2010-8-1 14:52 编辑
#include 'array.au3'

TCPStartup()
Global Const $__TCP_WINDOW = GUICreate('')
Global $hWs2_32 = -1


_TCP_Server_Create(0, '0.0.0.0')
MsgBox(4096, '', '现在服务端创建的TCP连接使用的端口是?该如何获取呢?')

While 1
        Sleep(100)
WEnd


Func _TCP_Server_Create($iPort, $sIP = "0.0.0.0")
        $hListenSocket = _ASocket()
        _ASockSelect($hListenSocket, $__TCP_WINDOW, 0x0400, 8)
        _ASockListen($hListenSocket, $sIP, $iPort)
        Return $hListenSocket
EndFunc   ;==>_TCP_Server_Create

Func _ASocket($iAddressFamily = 2, $iType = 1, $iProtocol = 6)
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        Local $hSocket = DllCall($hWs2_32, "uint", "socket", "int", $iAddressFamily, "int", $iType, "int", $iProtocol)
        If @error Then
                SetError(1, @error)
                Return -1
        EndIf
        If $hSocket[0] = -1 Then
                SetError(2, _WSAGetLastError())
                Return -1
        EndIf
        Return $hSocket[0]
EndFunc   ;==>_ASocket

Func _ASockSelect($hSocket, $hWnd, $uiMsg, $iEvent)
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        Local $iRet = DllCall($hWs2_32, "int", "WSAAsyncSelect", "uint", $hSocket, "hwnd", $hWnd, "uint", $uiMsg, "int", $iEvent)
        If @error Then
                SetError(1, @error)
                Return False
        EndIf
        Return True
EndFunc   ;==>_ASockSelect

Func _ASockListen($hSocket, $sIP, $uiPort, $iMaxPending = 5)
        Local $iRet
        Local $stAddress
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        $stAddress = __SockAddr($sIP, $uiPort)
        If @error Then
                SetError(@error, @extended)
                Return False
        EndIf

        $iRet = DllCall($hWs2_32, "int", "bind", "uint", $hSocket, "ptr", DllStructGetPtr($stAddress), "int", DllStructGetSize($stAddress))
        If @error Then
                SetError(3, @error)
                Return False
        EndIf
        If $iRet[0] <> 0 Then
                $stAddress = 0
                SetError(4, _WSAGetLastError())
                Return False
        EndIf

        $iRet = DllCall($hWs2_32, "int", "listen", "uint", $hSocket, "int", $iMaxPending)
        If @error Then
                SetError(5, @error)
                Return False
        EndIf
        If $iRet[0] <> 0 Then
                $stAddress = 0
                SetError(6, _WSAGetLastError())
                Return False
        EndIf
        Return True
EndFunc   ;==>_ASockListen

Func __SockAddr($sIP, $iPort, $iAddressFamily = 2)
        Local $iRet
        Local $stAddress
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        $stAddress = DllStructCreate("short;ushort;uint;char[8]")
        If @error Then
                SetError(1, @error)
                Return False
        EndIf
        DllStructSetData($stAddress, 1, $iAddressFamily)
        $iRet = DllCall($hWs2_32, "ushort", "htons", "ushort", $iPort)
        DllStructSetData($stAddress, 2, $iRet[0])
        $iRet = DllCall($hWs2_32, "uint", "inet_addr", "str", $sIP)
        If $iRet[0] = 0xffffffff Then
                $stAddress = 0
                SetError(2, _WSAGetLastError())
                Return False
        EndIf
        DllStructSetData($stAddress, 3, $iRet[0])
        Return $stAddress
EndFunc   ;==>__SockAddr

Func _WSAGetLastError()
        If $hWs2_32 = -1 Then $hWs2_32 = DllOpen("Ws2_32.dll")
        Local $iRet = DllCall($hWs2_32, "int", "WSAGetLastError")
        If @error Then
                ConsoleWrite("+> _WSAGetLastError(): WSAGetLastError() failed. Script line number: " & @ScriptLineNumber & @CRLF)
                SetExtended(1)
                Return 0
        EndIf
        Return $iRet[0]
EndFunc   ;==>_WSAGetLastError
发表于 2010-7-31 09:04:00 | 显示全部楼层
帮顶下,太深奥了
发表于 2010-7-31 09:48:33 | 显示全部楼层
开始监听或者连接后,你你设置的0 在读出来,就可以得到系统赋予的端口号.
getsockname(........)
$stAddress里的htons
发表于 2010-7-31 10:15:43 | 显示全部楼层
_MakeLong 为什么不用位移 *10000和左移4位,效率应该不同.

没有线程池甚至连工作线程都没有.
你就没有试试启动1000个客户端.
CONNECT后立即CLOSE,你的服务端还能正常工作吗?
redim的效率非常低,而且内存泄漏严重.
这种方法可能导致服务端不能正常长时间运行.
      $iRet = _WSAGetLastError()
        If $iRet = 10035 Then
                Return True
        EndIf
        SetExtended(1)
        Return True
这段更让人看不懂.
既然WSAGetLastError不等于0也不等于WSAEISCONN (10056) ,顶多也只能说明正在连接中.
没看到有设置CONNECT超时,那么你CONN时,是不是整个程序就要等待6秒左右的无法响应?(如果IP不存在.)


仅提下建议,别介意. 其实我很想看到牛人,能用AU3这种单线程 写出 SOCKET服务,所以说了这么多.
发表于 2010-7-31 10:22:07 | 显示全部楼层
指定端口就失去这个问题的意义了。
呵呵
破帽遮颜 发表于 2010-7-31 00:40


是我刚好有这个需求,需要指端口来发送数据
发表于 2010-7-31 10:30:18 | 显示全部楼层
深奥,还未接触,,,,加油,努力
 楼主| 发表于 2010-7-31 17:31:23 | 显示全部楼层
_MakeLong 为什么不用位移 *10000和左移4位,效率应该不同.

没有线程池甚至连工作线程都没有.
你就没有试 ...
akmm88 发表于 2010-7-31 10:15



呵呵,谢谢回复。
这个UDF并不是我写的。我只是针对系统随机分配端口,所以放上来一个例子。
你能帮忙解决这个问题吗?拜托了。^_^
发表于 2010-7-31 17:52:53 | 显示全部楼层
回复 7# 破帽遮颜

这个很漂亮~~
发表于 2010-7-31 17:53:58 | 显示全部楼层
没弄明白,要获取的是sever的端口,还是Client的端口?
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-5-16 09:31 , Processed in 0.088203 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表