nmgwddj 发表于 2012-3-20 10:54:32

Tcp通讯,一服务端多客户端模式下的问题。(已解决)

本帖最后由 nmgwddj 于 2012-3-21 14:09 编辑

首先做一个简单的图给大家看一下我所设想的思路,大家帮忙看看是否有什么错误。



在经过这样设计以后,代码是下面这样写的。

#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
;服务端程序
#region ### START Koda GUI section ### Form=
$IpAddr = @IPAddress1
$Port = 10002
TCPStartup();开始 TCP 服务
$Socket = TCPListen($IpAddr, $Port)
$Form1 = GUICreate("Form1", 361, 265)
$Edit = GUICtrlCreateEdit("", 8, 8, 345, 217, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $ES_WANTRETURN, $WS_VSCROLL))
$Button1 = GUICtrlCreateButton("Exit", 280, 232, 75, 25)
GUISetState(@SW_SHOW)
#endregion ### END Koda GUI section ###

$ConnectedSocket = -1;先初始化一下$ConnectedSocket变量
While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
                Case $GUI_EVENT_CLOSE, $Button1
                        TCPCloseSocket($ConnectedSocket)
                        TCPShutdown()
                        Exit

        EndSwitch
        If $ConnectedSocket = -1 Then
                $ConnectedSocket = TCPAccept($Socket)
        EndIf
        $sRecv = TCPRecv($ConnectedSocket, 2048, 1)
        If $sRecv <> '' Then;如果接收的数据包不为空
                GUICtrlSetData($Edit, BinaryToString($sRecv, 4));将客户端发送的信息写到edit框中
                _SendToClient('已经收到你的消息,给你发送数据库里的信息');在已经建立的套接字上给客户机发送消息
                $ConnectedSocket = -1
                TCPCloseSocket($ConnectedSocket);发送过一次消息后关闭此连接。
        EndIf
WEnd
Func _SendToClient($Info)
        If $Info = "" Then Return
        $sMsg = StringToBinary($Info, 4)
        TCPSend($ConnectedSocket, $sMsg)
EndFunc   ;==>_SendToClient


#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiIPAddress.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#region ### START Koda GUI section ### Form=
;客户端程序
Global $sEndSocket
TCPStartup();开始 TCP 服务.
$Form2 = GUICreate("窗体1", 353, 102)
$Input1 = GUICtrlCreateInput("", 88, 72, 121, 21)
$sEnd = GUICtrlCreateButton("sEnd", 224, 72, 75, 25)
$IPAddress1 = _GUICtrlIpAddress_Create($Form2, 120, 8, 130, 21)
_GUICtrlIpAddress_Set($IPAddress1, "192.168.3.247")
$Label1 = GUICtrlCreateLabel("ServerIP:", 72, 16, 48, 17)
$Label2 = GUICtrlCreateLabel("Port:", 88, 40, 26, 17)
$Input2 = GUICtrlCreateInput("10002", 120, 40, 49, 21)
GUISetState(@SW_SHOW)
#endregion ### END Koda GUI section ###

While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
                Case $GUI_EVENT_CLOSE
                        Exit
                Case $sEnd
                        SendDataToServer(GUICtrlRead($Input1))

        EndSwitch
        $sRecv = TCPRecv($sEndSocket, 2048, 1);从SendDataToServer中已经连接的套接字上接收数据。
        If $sRecv <> '' Then;如果接收的数据包不为空
                MsgBox(0, '', BinaryToString($sRecv, 4))
        EndIf
WEnd
Func SendDataToServer($sData)
        Local $ServerIP = _GUICtrlIpAddress_Get($IPAddress1)
        Local $Port = GUICtrlRead($Input2)
        $sEndSocket = TCPConnect($ServerIP, $Port)
        If @error Then
                MsgBox(4112, "错误", "TCP连接失败,服务端未启用!错误代码: " & @error)
        Else
                If @error Or $sData = "" Then Return
                $sMsg = StringToBinary($sData, 4)
                TCPSend($sEndSocket, $sMsg)
        EndIf
EndFunc   ;==>SendDataToServer


上面代码大家帮忙看下是否有缺陷?现在虽然可以实现多台客户机与服务端连接。


但是在客户端每次发送一条数据的时候,都要与服务端重新建立一个新的连接(是因为服务端每次接收到消息以后都会TCPCloseSocket掉连接,为了正确连接其他机器。)。这样会不会导致服务端连接数超出?
又或者说我代码设计的有问题呢?
或者说如何让每一台客户机与服务器只单线连接进行通讯?请各位指教谢谢。

jinefo 发表于 2012-3-20 20:07:23

好吧,不废话,发个例子让你消化一下。

楼上风云 发表于 2012-3-20 11:40:16

回复 1# nmgwddj
有无可能将空闲客户端变服次级服务端?类似P2P?

nmgwddj 发表于 2012-3-20 11:43:25

回复 2# 楼上风云


    貌似现在还达不到那种水平,不过我看有类似广播包的udf,应该可以实现p2p。

楼上风云 发表于 2012-3-20 11:45:50

回复 3# nmgwddj


    记得官网里有P2P,你可以参考下

楼上风云 发表于 2012-3-20 11:54:23

回复 3# nmgwddj

不知以下链接,是否有帮助?
    http://www.autoitscript.com/forum/topic/120056-tcp-p2p-event-driven/page__fromsearch__1

nmgwddj 发表于 2012-3-20 12:13:53

本帖最后由 nmgwddj 于 2012-3-20 12:15 编辑

回复 5# 楼上风云


    。。别人写的东西真的要耗费很大精力去看,我先看看单线通信他是如何实现的。

    E文,头痛的事情!!!

xms77 发表于 2012-3-20 12:43:23

曾经用UDP做过服务器端和客户端软件,至今还在公司的机器电脑上用着呢,TCP没有用过,因为服务器是我的电脑,晚上和星期六,日是关机的,所以就用UDP来通讯,不需要连接。

jinefo 发表于 2012-3-20 14:23:33

建议使用do来做循环,while等你程序大就知道蛋疼了。本机不知道是什么原因无法监听TCP发包问题,找了自己的TCP还是一样。估计是我系统出问题了。

随手修改了一下,先把代码发上来给你看看,服务端
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
;服务端程序
#region ### START Koda GUI section ### Form=
Global $IpAddr = @IPAddress1
Global $Port = 10002
Global $ConnectedSocket = -1;先初始化一下$ConnectedSocket变量

$Form1 = GUICreate("Form1", 361, 265)
$Edit = GUICtrlCreateEdit("", 8, 8, 345, 217, BitOR($ES_AUTOVSCROLL, $ES_AUTOHSCROLL, $ES_WANTRETURN, $WS_VSCROLL))
$Button1 = GUICtrlCreateButton("Exit", 280, 232, 75, 25)
GUISetState(@SW_SHOW)
#endregion ### END Koda GUI section ###

TCPStartup();开始 TCP 服务
$Socket = TCPListen($IpAddr, $Port)
If $Socket = -1 Then Exit ;如果套接字监听失败就退出


Do
$ConnectedSocket = TCPAccept($Socket)
Until $ConnectedSocket <> -1

While 1
      $nMsg = GUIGetMsg()
      Switch $nMsg
                Case $GUI_EVENT_CLOSE, $Button1
                        TCPCloseSocket($ConnectedSocket)
                        TCPShutdown()
                        Exit

      EndSwitch
      $sRecv = TCPRecv($ConnectedSocket, 2048 * 1)
      If $sRecv <> '' Then;如果接收的数据包不为空
                GUICtrlSetData($Edit, BinaryToString($sRecv, 4));将客户端发送的信息写到edit框中
                _SendToClient('已经收到你的消息,给你发送数据库里的信息');在已经建立的套接字上给客户机发送消息
      EndIf
WEnd
Func _SendToClient($Info)
      If $Info = "" Then Return
      $sMsg = StringToBinary($Info, 4)
      TCPSend($ConnectedSocket, $sMsg)
                TCPCloseSocket($ConnectedSocket);发送过一次消息后关闭此连接。
EndFunc   ;==>_SendToClient客户端#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiIPAddress.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#region ### START Koda GUI section ### Form=
;客户端程序
Global $sEndSocket
Global $ip = @IPAddress1
Global $sEndSocket = -1
$Form2 = GUICreate("窗体1", 353, 102)
$Input1 = GUICtrlCreateInput("", 88, 72, 121, 21)
$sEnd = GUICtrlCreateButton("sEnd", 224, 72, 75, 25)
$IPAddress1 = _GUICtrlIpAddress_Create($Form2, 120, 8, 130, 21)
_GUICtrlIpAddress_Set($IPAddress1, "127.0.0.1")
$Label1 = GUICtrlCreateLabel("ServerIP:", 72, 16, 48, 17)
$Label2 = GUICtrlCreateLabel("Port:", 88, 40, 26, 17)
$Input2 = GUICtrlCreateInput("10002", 120, 40, 49, 21)
GUISetState(@SW_SHOW)
#endregion ### END Koda GUI section ###
TCPStartup();开始 TCP 服务.
$sEndSocket = TCPConnect($ip, GUICtrlRead($Input2))

Do
        _recv()

Until $sEndSocket = -1

While 1
      $nMsg = GUIGetMsg()
      Switch $nMsg
                Case $GUI_EVENT_CLOSE
                        Exit
                Case $sEnd
                Local $sdata = GUICtrlRead($sEnd)
If $read = "" Then
Return
EndIf
TCPSend($sEndSocket, StringToBinary($sdata, 4))
      EndSwitch
WEnd

Func _recv()
$sRecv = TCPRecv($sEndSocket,1024 * 50,1)
If $sRecv <> "" Then
MsgBox(0, '', BinaryToString($sRecv, 4))
EndIf
        EndFunc

               

nmgwddj 发表于 2012-3-20 16:59:32

本帖最后由 nmgwddj 于 2012-3-20 17:03 编辑

回复 8# jinefo


    是这样的,由于有很多客户机连接,如果服务端一直使用一个TCPAccept创建的连接话,那么第二个以后运行的客户端是无法连接到服务器发送数据的,因为服务端一直只有这一个不变的TCPAccept返回值。

如果服务端每次接收完客户端的数据就注销一次连接,那么其他客户端连接的时候才能正常连接上。 可以这样会造成客户端也无法使用原来的套接字来发送数据了,所以客户端还要重新与服务端建立连接(TCPConnect)这样就会每次发送数据都重新连接一次服务器(因为我要保持客户端与服务端的连接)。也就是我1#代码中的例子了,1#的例子不知道会不会造成服务端连接数过多而导致程序崩溃系统无法上网等问题。

m61918424 发表于 2012-3-20 18:02:29

顶,不错,学习学习

guowenfu 发表于 2012-3-21 11:30:25

回复 11# jinefo


    谢谢,小弟最近也在找这方面的支持,急需啊。

nmgwddj 发表于 2012-3-21 14:09:03

回复 11# jinefo


    原来是数组,懂了懂了,3Q

liui 发表于 2012-3-21 14:43:34

高手好多啊~谢谢楼主和11楼

lovecity 发表于 2012-7-4 17:07:17

真的不错,,,有这么多高手,,,论坛里,就是要这样,
页: [1] 2 3
查看完整版本: Tcp通讯,一服务端多客户端模式下的问题。(已解决)