[已解决]有没有内置函数实现UDP单端口通信的例子?
本帖最后由 gyp2000 于 2023-5-16 00:09 编辑内置函数实现UDP单端口通信
服务端和客户端都仅使用一个端口。
客户端使用系统分配的随机端口。
图例:
本帖最后由 白嫖之黑 于 2023-5-6 03:27 编辑
一般不都是单端口吗。套接字可以实现通讯 白嫖之黑 发表于 2023-5-6 01:08
一般不都是单端口吗。套接字可以实现通讯
目前AU3里, TCP是单端口。UDP的话,自己造轮子也可以实现单端口。
如果仅使用内置函数,目前还没看到 ,通过内置函数实现UDP单端口通讯的例子。 本帖最后由 gyp2000 于 2023-5-16 00:28 编辑
#include <GUIConstantsEx.au3>
Global $S_Socket, $C_Socket
Example()
Func Example()
UDPStartup()
Local $sReceived, $maxlen
Local $hGUI = GUICreate("UDP通讯示例")
Local $idEXIT = GUICtrlCreateButton("退出", 310, 370, 85, 25)
Local $Label1 = GUICtrlCreateLabel("", 10, 10, 160, 25)
Local $Label2 = GUICtrlCreateLabel("", 10, 42, 160, 25)
Local $Label3 = GUICtrlCreateLabel("Server 返回消息:", 10, 74, 160, 25)
GUISetState(@SW_SHOW, $hGUI)
$S_Socket = _UDPBind("0.0.0.0", 0)
If @error Then Exit MsgBox(0, "", "服务端:" & @CRLF & "无法绑定, 错误代码: " & @error)
GUICtrlSetData($Label1, "Server 监听端口:" & @extended)
$C_Socket = _UDPOpen("127.0.0.1", $S_Socket)
If @error Then Exit MsgBox(0, "", "客户端:" & @CRLF & "无法连接, 错误代码: " & @error)
GUICtrlSetData($Label2, "Client 监听端口:" & @extended)
AdlibRegister("_Time", 1000)
While 1
Switch GUIGetMsg()
Case $GUI_EVENT_CLOSE, $idEXIT
ExitLoop
EndSwitch
$maxlen = _Datelen($S_Socket)
If $maxlen Then
$sReceived = _UDPRecv($S_Socket, $maxlen, 2)
$S_Socket = $sReceived
$S_Socket = $sReceived
UDPSend($S_Socket, @HOUR & ":" & @MIN & ":" & @SEC)
EndIf
$maxlen = _Datelen($C_Socket)
If $maxlen Then
$sReceived = _UDPRecv($C_Socket, $maxlen)
GUICtrlSetData($Label3, "Server 返回消息:" & $sReceived)
EndIf
WEnd
UDPCloseSocket($S_Socket)
UDPCloseSocket($C_Socket)
UDPShutdown()
GUIDelete($hGUI)
EndFunc ;==>Example
Func _Time()
UDPSend($C_Socket, @SEC)
EndFunc ;==>_Time
Func _UDPOpen($sIPAddr, $iPort)
Local $aSocket = _UDPBind("0.0.0.0", 0)
$aSocket = $sIPAddr
$aSocket = $iPort
Return SetError(@error, @extended, $aSocket)
EndFunc ;==>_UDPOpen
Func _UDPBind($sIPAddr, $iPort)
Local $aSocket, $loop
If $iPort = 0 Then
Do
$loop += 1
$iPort = Random(49152, 65535, 1)
$aSocket = UDPBind($sIPAddr, $iPort)
If $loop > 15000 Then ExitLoop
Until @error <> 10048
Else
$aSocket = UDPBind($sIPAddr, $iPort)
EndIf
If @error Then Return SetError(@error, 0, $aSocket)
DllCall("Ws2_32.dll", "long", "setsockopt", "handle", $aSocket, "long", 0xffff, "long", 0x20, "long*", 1, "long*", 4) ;允许广播地址
Return SetError(0, $aSocket, $aSocket)
EndFunc ;==>_UDPBind
Func _UDPRecv(ByRef $aSocket, $maxlen, $flag = 0)
Local $sRecv = UDPRecv($aSocket, $maxlen, $flag)
Return SetError(@error, 0, $sRecv)
EndFunc ;==>_UDPRecv
Func _Datelen(ByRef $aSocket)
Local $aRet = DllCall("Ws2_32.dll", "int", "ioctlsocket", "uint", $aSocket, "long", 0x4004667F, "ulong*", 0) ;查询接收缓冲区数据长度
If Not @error Then Return SetError(0, 0, $aRet)
Return SetError(@error, 0, 0)
EndFunc ;==>_Datelen
示例里的端口随机,使用了随机函数实现。这样可以让代码易读一些。
UDPRecv函数在无数据的时候会堵塞100毫秒,所以读取前检查缓冲区长度再读取数据,这样可以避免堵塞的发生。
:face (1):
页:
[1]