jycel 发表于 2009-9-22 11:13:26

[已解决]TCP通信(局域网聊天)数据转发失败

本帖最后由 jycel 于 2009-9-24 10:31 编辑


如图,服务端写成界面,只不过方便现在检查错误
在$Combo这个发送对像中,临时设置的几个IP地址,其中所有人是必须的
在测试过程中,对所有人发送信息测试成常,但是如果对指定IP却发送成功,接收不到,在发送同时自己也会收到发送的消息如图所示
在发送信息时,我是以“接收对像|消息|本机IP”来定义
服务端接收数据通过StringSplit拆分分为三份,如果值为所有人,就转发给所有人。如果非所有人,就发送给值一IP
请大家帮忙检查下问题出在那儿了,谢谢!
解决方法:需要修改的地方,其实答案就在以前的代码中~
If $lh<>"所有人" Then
$iIndex = _ArraySearch($aConnected, $lh, 1, 0, 0, 0, 1, 1)
$sMsg = StringToBinary($lh&"|"&$lh, 4)
TCPSend($aConnected[$iIndex], $sMsg)   ; 发送信息
;TCPSend($lh, $sMsg)                                       
If @error Then
    GUICtrlSetData($Label1, "消息转发失败!")
Else
   GUICtrlSetData($Label1, "消息转发成功!")
EndIf
Else       
$sMsg = StringToBinary($lh&"|"&$lh, 4)
For $i = 1 To $aConnected
        $iIP = $aConnected[$i]
               TCPSend($aConnected[$i], $sMsg)
Next       
GUICtrlSetData($Label1, "群发消息转发成功!")       
EndIf

服务端源码:

#include <ComboConstants.au3>
#include <GUIConstants.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
Global $Edit1,$Edit2, $Edit3, $Combo1, $Label1
Local $sSrvIP = @IPAddress1, $iPort = 65432
#Region ### START Koda GUI section ### Form=c:\documents and settings\administrator\桌面\tcp.kxf
$Form1 = GUICreate("TCP-Server", 522, 327, 522, 398)
$Group1 = GUICtrlCreateGroup("", 8, 0, 505, 318)
$Edit1 = GUICtrlCreateEdit("历史消息:"&"本机用户名→"&@ComputerName, 16, 16, 489, 20,BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_HSCROLL))
GUICtrlSetState(-1,$GUI_DISABLE)
$Edit2 = GUICtrlCreateEdit("", 16, 40, 489, 217,BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_VSCROLL))
;GUICtrlSetState(-1,$GUI_DISABLE)
$Label1 = GUICtrlCreateLabel("", 16, 264, 490, 17)
GUICtrlSetColor(-1, 0xFF0000)
$Label2 = GUICtrlCreateLabel("→", 16, 292, 19, 17)
GUICtrlSetColor(-1, 0x000080)
$Combo1 = GUICtrlCreateCombo("", 40, 288, 105, 25)
GUICtrlSetData(-1,"所有人|192.168.0.55|192.168.0.136|192.168.0.254","所有人")
$Edit3 = GUICtrlCreateEdit("", 152, 288, 273, 20, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN))

$Button1 = GUICtrlCreateButton("发送", 432, 288, 73, 20, $BS_DEFPUSHBUTTON)
GUICtrlSetColor(-1, 0x0000FF)
GUICtrlCreateGroup("", -99, -99, 1, 1)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

Global $MainSocket, $aConnected = []
TCPStartUp()

$MainSocket = TCPListen($sSrvIP, $iPort, 100)
If $MainSocket = -1 Then Exit   ; 创建监听不成功就退出
GUICtrlSetData($Label1, "正在等待客户端连接……")

While 1
        Switch GUIGetMsg()
                Case $GUI_EVENT_CLOSE
                        _ext()
                Case $Button1
                        _send()
        EndSwitch

        Accept()
        Recv()
WEnd
Exit

Func _ext()
        TCPCloseSocket($MainSocket)
        TCPShutdown()
        Exit
EndFunc

Func _send()
        Local $sMsg, $iIP, $iIndex, $sEdit

        $sMsg = GUICtrlRead($Edit3)
        $iIP =GUICtrlRead($Combo1)
        $iIndex = _ArraySearch($aConnected, $iIP, 1, 0, 0, 0, 1, 1)
        If $sMsg = "" Then
                GUICtrlSetData($Label1, "消息不能为空!")
        ElseIf $iIP = "所有人" Then   ; 未输入IP,开始广播
                $sEdit = "→【"&GUICtrlRead($Combo1)&"】:"& $sMsg & @CRLF & GUICtrlRead($Edit2)
                GUICtrlSetData($Edit2, $sEdit)
                $sMsg = StringToBinary($sMsg, 4)
                For $i = 1 To $aConnected
                        $iIP = $aConnected[$i]
                        TCPSend($aConnected[$i], $sMsg)
                Next
                GUICtrlSetData($Label1, "广播完毕! 当前连接: " & $aConnected)
        ElseIf $iIndex = -1 Then
                GUICtrlSetData($Label1, $iIP & " 客户端尚未连接!")
        Else
                $sEdit = $iIP & " > " & $sMsg & @CRLF & GUICtrlRead($Edit2)
                GUICtrlSetData($Edit2, $sEdit)
                $sMsg = StringToBinary($sMsg, 4)
                TCPSend($aConnected[$iIndex], $sMsg)   ; 发送信息
                If @error Then
                        GUICtrlSetData($Label1, $iIP & " 消息发送失败!")
                Else
                        GUICtrlSetData($Label1, $iIP & " 消息发送成功!")
                EndIf
        EndIf

        GUICtrlSetData($Edit3, "")
        GUICtrlSetState($Edit3, $GUI_FOCUS)
        Return
EndFunc

Func Accept()
        Local $ConnectedSocket, $sEdit

        $ConnectedSocket = TCPAccept($MainSocket)
        If $ConnectedSocket <> -1 Then
                $aConnected += 1
                ReDim $aConnected[$aConnected + 1]
                $aConnected[$aConnected] = $ConnectedSocket
                $aConnected[$aConnected] = SocketToIP($ConnectedSocket)
                ;$sEdit = "→【" & $aConnected[$aConnected] & "】:上线"& @CRLF & GUICtrlRead($Edit2)
                ;GUICtrlSetData($Edit2, $sEdit)
                GUICtrlSetData($Label1, "")
                GUICtrlSetData($Label1, "【" & $aConnected[$aConnected] & "】:连接成功!")               
        EndIf

        Return
EndFunc

Func Recv()
        Local $sRecv, $sEdit, $i = 1

        While $i <= UBound($aConnected) - 1
                $sRecv = TCPRecv($aConnected[$i], 2048, 1);256)
                If @error Then   ; 客户端已关闭
                        ;$sEdit = "→【" & $aConnected[$i] & "】:下线"& @CRLF & GUICtrlRead($Edit2)
                        ;GUICtrlSetData($Edit2, $sEdit)
                        GUICtrlSetData($Label1, "")
                        GUICtrlSetData($Label1, "【" & $aConnected[$i] & "】:已退出")
                        TCPCloseSocket($aConnected[$i])
                        _ArrayDelete($aConnected, $i)
                        $aConnected -= 1
                Else
                        If $sRecv <> "" Then   ; 接收到客户端发送数据,开始处理
                                $sRecv = BinaryToString($sRecv, 4)
                                $sEdit ="→【" & $aConnected[$i] & "】: " & $sRecv & @CRLF & GUICtrlRead($Edit2)
                                $lh=StringSplit($sRecv,"|")
                                        If $lh<>"所有人" Then
                                                        $sMsg = StringToBinary($lh&"|"&$lh, 4)
                                                        TCPSend($lh, $sMsg)
                                                        TCPSend($lh, $sMsg)
                                                        GUICtrlSetData($Label1,"向"&$lh&"转发成功 向"&$lh&"回复成功")       
                                        Else       
                                                        $sMsg = StringToBinary($lh&"|"&$lh, 4)
                                                                For $i = 1 To $aConnected
                                                                        $iIP = $aConnected[$i]
                                                                        TCPSend($aConnected[$i], $sMsg)
                                                                Next       
                                        EndIf
                               
                                GUICtrlSetData($Edit2, $sEdit)
                        EndIf
                        $i += 1
                EndIf
        WEnd

        Return
EndFunc


; Function to return IP Address from a connected socket.
;----------------------------------------------------------------------
Func SocketToIP($Shocket)
        Local $SockAddr, $aRet

        $SockAddr = DllStructCreate("short;ushort;uint;char")

        $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $Shocket, "ptr", DllStructGetPtr($SockAddr), "int*", DllStructGetSize($SockAddr))
        If NOT @error AND $aRet = 0 Then
                $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($SockAddr, 3))
                If NOT @error Then $aRet = $aRet
        Else
                $aRet = 0
        EndIf

        Return $aRet
EndFunc   ;==>SocketToIP


客户端:

#include <ButtonConstants.au3>
#include <ComboConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
Global $Edit1, $Edit2, $Label1
Local $sRecv, $sEdit, $sSrvIP, $iPort = 65432
$sSrvIP = "192.168.0.136"
#Region ### START Koda GUI section ### Form=c:\documents and settings\administrator\桌面\tcp.kxf
$Form1 = GUICreate("TCP-Client", 522, 327, 522, 398)
$Group1 = GUICtrlCreateGroup("", 8, 0, 505, 318)
$Edit1 = GUICtrlCreateEdit("历史消息:"&"本机用户名→"&@ComputerName, 16, 16, 489, 20, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN))
GUICtrlSetState(-1,$GUI_DISABLE)
$Edit2 = GUICtrlCreateEdit("", 16, 40, 489, 217, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN))
$Label1 = GUICtrlCreateLabel("正在连接……", 16, 264, 490, 17)
GUICtrlSetColor(-1, 0xFF0000)
$Label2 = GUICtrlCreateLabel("→", 16, 292, 19, 17)
GUICtrlSetColor(-1, 0x000080)
$Combo1 = GUICtrlCreateCombo("", 40, 288, 105, 25)
GUICtrlSetData(-1,"所有人|192.168.0.65|192.168.0.136|192.168.0.254","所有人")
$Edit3 = GUICtrlCreateEdit("", 152, 288, 273, 20, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN))
$Button1 = GUICtrlCreateButton("发送", 432, 288, 73, 20)
GUICtrlSetColor(-1, 0x0000FF)
GUICtrlCreateGroup("", -99, -99, 1, 1)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
;-------------------------------------------
Global $Socket
TCPStartUp()

$Socket = TCPConnect($sSrvIP, $iPort); 创建一个套接字连接到已经存在的服务器
If $Socket = -1 Then
        MsgBox(0, "提示", "服务端未开启请联系管理员!", 0, $Form1)
        _ext()
EndIf
GUICtrlSetData($Label1, "连接["&$sSrvIP&"]服务器成功")

While 1
        Switch GUIGetMsg()
                Case $GUI_EVENT_CLOSE
                        _ext()
                Case $Button1
                        _send()
        EndSwitch

        $sRecv = TCPRecv($Socket, 2048, 1)
        If @error Then
                MsgBox(0, "提示", "服务端已关闭!", 0, $Form1)
                _ext()
        ElseIf $sRecv <> "" Then   ; 把接收的内容放到文本框内
                $sRecv = BinaryToString($sRecv, 4)
                $lh=StringSplit($sRecv,"|")
                $sEdit = "→【"& $lh & "】: " & $lh & @CRLF & GUICtrlRead($Edit2)
                GUICtrlSetData($Edit2, $sEdit)
        EndIf
WEnd
Exit

;-------------------------------------------
Func _ext()
        TCPCloseSocket($Socket)
        TCPShutdown()
        Exit
EndFunc

;-------------------------------------------
Func _send()
        Local $sMsg, $sEdit

        $sMsg = GUICtrlRead($Edit3)
        If $sMsg = "" Then
                GUICtrlSetData($Label1, "消息不能为空!")
        Else
                $sEdit = "→【"&GUICtrlRead($Combo1)&"】:"& $sMsg & @CRLF & GUICtrlRead($Edit2)
                ;GUICtrlSetData($Edit2, $sEdit)
                $sMsg = StringToBinary(GUICtrlRead($Combo1)&"|"&$sMsg&"|"&@IPAddress1, 4)
                TCPSend($Socket,$sMsg)   ; 发送信息
                If @error Then
                        GUICtrlSetData($Label1, "消息发送失败!")
                Else
                        GUICtrlSetData($Label1, "消息发送成功!")
                EndIf
        EndIf

        GUICtrlSetData($Edit3, "")
        GUICtrlSetState($Edit3, $GUI_FOCUS)
        Return
EndFunc

jycel 发表于 2009-9-22 11:19:32

如果没有多的电脑,测试时可以直接向本机IP发送即可

jycel 发表于 2009-9-22 14:24:03

本帖最后由 jycel 于 2009-9-22 14:26 编辑

我的判断没问题啊?搞了一天还是没有解决!这里收到消息是所有人就转发所有在线,不是就按接收数据处理判断发给那个IP,就是发不出去~~还缺少条件或什么的么?

If $lh<>"所有人" Then
   $sMsg = StringToBinary($lh&"|"&$lh, 4)
TCPSend($lh, $sMsg)
TCPSend($lh, $sMsg)
GUICtrlSetData($Label1,"向"&$lh&"转发成功 向"&$lh&"回复成功")      
Else      
   $sMsg = StringToBinary($lh&"|"&$lh, 4)
          For $i = 1 To $aConnected
                $iIP = $aConnected[$i]
                TCPSend($aConnected[$i], $sMsg)
         Next      
EndIf

a62105400 发表于 2009-9-23 03:23:24

我看看哈..我也正在写这个网吧用的...我那个如果有人连接的话 服务端会自动跳到那个人的IP 并变颜色   本来开始用的时候服务端 CPU只有5不到的 后来工作机换了下系统CPU就跳上去了 现在必须重些了

a62105400 发表于 2009-9-23 04:56:00

你写的这个不行啊 TCP连接只能1个端口对一个client不能一个端口接受很多client的数据你这个顶多是1对1的而且还有出错...

jycel 发表于 2009-9-23 10:28:49

楼上测试我的代码没有?服务端怎么可能无法接收多个客户机的信息?我这不但能接收,还能全部转发,我这问题就是能向所有机子发送信息却不能对单个发送信息~~还是等高人来找下问题

kn007 发表于 2009-9-23 13:42:00

辛苦了

jycel 发表于 2009-9-23 14:18:18

本帖最后由 jycel 于 2009-9-23 14:24 编辑

辛苦了
kn007 发表于 2009-9-23 13:42 http://www.autoitx.com/images/common/back.gif
:face (13): 我还以为你来帮我解决问题了呢
:face (36):问题一直未解决!找帽子呢~~大忙人

jycel 发表于 2009-9-24 10:00:44

哈哈!今早做卫生时灵感一下就来了:face (13):随时都把没解决的问题挂到在~~~
答案就在以前的代码中~~
终于搞定了

a62105400 发表于 2009-9-27 04:45:30

恩。。。。你这个是对的我原以为一个端口只能连一个client,刚测试了一个端口2个client 也行 我要重写了 n你那个connected的数组有点难看懂 我也要写这一步,写好那步就差不多了。。。 我原来写的一个是服务端跟客户端反过来 让客户端开个端口 服务端直接连的

menfan 发表于 2009-9-27 08:34:11

呵呵,学习一下。。

jycel 发表于 2009-9-27 10:13:42


目前测试如上图,我把IP转换成了昵称后,有点问题就是上线没问题,下线后,在线用户客户端列表中不清除下线用户!估计那儿判断有问题,还在测试中

a62105400 发表于 2009-9-28 01:55:40

这是我写好的 accept   andrecv   ,$n=0

If $ConnectedSocket[$n] = -1 Then
            $ConnectedSocket[$n] = TCPAccept($MainSocket)
            If $ConnectedSocket[$n] < 0 Then
                $ConnectedSocket[$n] = -1
            Else
                WinSetTitle($GOOEY, "", "我的服务器 - 用户端连接")
               $n+=1
            
            EndIf
         endif
         for $i=0 to $n-1 step 1
            
             $recv[$i] = TCPRecv($ConnectedSocket[$i], 512)
             if $recv[$i]<>"" then GUICtrlSetData($edit, GUICtrlRead($edit) & ">" & $recv[$i])
         next
            我写不出你那么复杂的数组。。。。

a62105400 发表于 2009-9-28 07:50:34

http://b24.photo.store.qq.com/http_imgload.cgi?/rurl4_b=4b8cfd8d67ec1bb3796bc32410b8367360f6ff2edfd88acdb6be8949431dcc4848e7ba7777a4ea782a501bc9b9433800a038c41b91ee6d686b739ca81654d07582432bbd52806349b2d0bb06809344dc60bde91d

jycel 发表于 2009-9-28 22:33:55

局域网的已经搞定了,是以昵称显示在线用户,但是用于外网的话会产生二个IP很郁闷一直搞不定,外网直接用IP来显示就不会出错,
下载地址:http://jycel.ys168.com
页: [1] 2
查看完整版本: [已解决]TCP通信(局域网聊天)数据转发失败