gyp2000 发表于 2023-5-5 11:35:36

[已解决]有没有内置函数实现UDP单端口通信的例子?

本帖最后由 gyp2000 于 2023-5-16 00:09 编辑

内置函数实现UDP单端口通信

服务端和客户端都仅使用一个端口。
客户端使用系统分配的随机端口。
图例:

白嫖之黑 发表于 2023-5-6 01:08:51

本帖最后由 白嫖之黑 于 2023-5-6 03:27 编辑

一般不都是单端口吗。套接字可以实现通讯

gyp2000 发表于 2023-5-6 19:11:24

白嫖之黑 发表于 2023-5-6 01:08
一般不都是单端口吗。套接字可以实现通讯

目前AU3里, TCP是单端口。UDP的话,自己造轮子也可以实现单端口。
如果仅使用内置函数,目前还没看到 ,通过内置函数实现UDP单端口通讯的例子。

gyp2000 发表于 2023-5-16 00:07:29

本帖最后由 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毫秒,所以读取前检查缓冲区长度再读取数据,这样可以避免堵塞的发生。



qq413774005 发表于 2023-8-12 21:10:13

:face (1):
页: [1]
查看完整版本: [已解决]有没有内置函数实现UDP单端口通信的例子?