找回密码
 加入
搜索
查看: 8946|回复: 17

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

[复制链接]
发表于 2009-9-22 11:13:26 | 显示全部楼层 |阅读模式
本帖最后由 jycel 于 2009-9-24 10:31 编辑


如图,服务端写成界面,只不过方便现在检查错误
在$Combo这个发送对像中,临时设置的几个IP地址,其中所有人是必须的
在测试过程中,对所有人发送信息测试成常,但是如果对指定IP却发送成功,接收不到,在发送同时自己也会收到发送的消息如图所示
在发送信息时,我是以“接收对像|消息|本机IP”来定义
服务端接收数据通过StringSplit拆分分为三份,如果值[1]为所有人,就转发给所有人。如果非所有人,就发送给值一IP
请大家帮忙检查下问题出在那儿了,谢谢!
解决方法:需要修改的地方,其实答案就在以前的代码中~

If $lh[1]<>"所有人" Then
$iIndex = _ArraySearch($aConnected, $lh[1], 1, 0, 0, 0, 1, 1)
$sMsg = StringToBinary($lh[2]&"|"&$lh[3], 4)
TCPSend($aConnected[$iIndex][0], $sMsg)   ; 发送信息
;TCPSend($lh[1], $sMsg)                                        
If @error Then
    GUICtrlSetData($Label1, "消息转发失败!")
Else
   GUICtrlSetData($Label1, "消息转发成功!")
EndIf
Else        
$sMsg = StringToBinary($lh[2]&"|"&$lh[3], 4)
For $i = 1 To $aConnected[0][0]
        $iIP = $aConnected[$i][1]
               TCPSend($aConnected[$i][0], $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[1][2] = [[0]]
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[0][0]
                        $iIP = $aConnected[$i][1]
                        TCPSend($aConnected[$i][0], $sMsg)
                Next
                GUICtrlSetData($Label1, "广播完毕! 当前连接: " & $aConnected[0][0])
        ElseIf $iIndex = -1 Then
                GUICtrlSetData($Label1, $iIP & " 客户端尚未连接!")
        Else
                $sEdit = $iIP & " > " & $sMsg & @CRLF & GUICtrlRead($Edit2)
                GUICtrlSetData($Edit2, $sEdit)
                $sMsg = StringToBinary($sMsg, 4)
                TCPSend($aConnected[$iIndex][0], $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[0][0] += 1
                ReDim $aConnected[$aConnected[0][0] + 1][2]
                $aConnected[$aConnected[0][0]][0] = $ConnectedSocket
                $aConnected[$aConnected[0][0]][1] = SocketToIP($ConnectedSocket)
                ;$sEdit = "→【" & $aConnected[$aConnected[0][0]][1] & "】:上线"& @CRLF & GUICtrlRead($Edit2)
                ;GUICtrlSetData($Edit2, $sEdit)
                GUICtrlSetData($Label1, "")
                GUICtrlSetData($Label1, "【" & $aConnected[$aConnected[0][0]][1] & "】:连接成功!")                
        EndIf

        Return
EndFunc

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

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

        $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $Shocket, "ptr", DllStructGetPtr($SockAddr), "int*", DllStructGetSize($SockAddr))
        If NOT @error AND $aRet[0] = 0 Then
                $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($SockAddr, 3))
                If NOT @error Then $aRet = $aRet[0]
        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[2] & "】: " & $lh[1] & @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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×

评分

参与人数 1威望 +20 金钱 +100 贡献 +50 收起 理由
kn007 + 20 + 100 + 50 辛苦辛苦!

查看全部评分

 楼主| 发表于 2009-9-22 11:19:32 | 显示全部楼层
如果没有多的电脑,测试时可以直接向本机IP发送即可
 楼主| 发表于 2009-9-22 14:24:03 | 显示全部楼层
本帖最后由 jycel 于 2009-9-22 14:26 编辑

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

 If $lh[1]<>"所有人" Then
   $sMsg = StringToBinary($lh[2]&"|"&$lh[3], 4)
  TCPSend($lh[1], $sMsg)
  TCPSend($lh[3], $sMsg)
  GUICtrlSetData($Label1,"向"&$lh[1]&"转发成功 向"&$lh[1]&"回复成功")        
Else        
   $sMsg = StringToBinary($lh[2]&"|"&$lh[3], 4)
          For $i = 1 To $aConnected[0][0]
                $iIP = $aConnected[$i][1]
                TCPSend($aConnected[$i][0], $sMsg)
         Next        
 EndIf
发表于 2009-9-23 03:23:24 | 显示全部楼层
我看看哈..我也正在写这个网吧用的...我那个如果有人连接的话 服务端会自动跳到那个人的IP 并变颜色   本来开始用的时候服务端 CPU只有5不到的 后来  工作机换了下系统  CPU就跳上去了 现在必须重些了
发表于 2009-9-23 04:56:00 | 显示全部楼层
你写的这个不行啊 TCP连接只能1个端口对一个client  不能一个端口接受很多client的数据  你这个顶多是1对1的  而且还有出错...
 楼主| 发表于 2009-9-23 10:28:49 | 显示全部楼层
楼上测试我的代码没有?服务端怎么可能无法接收多个客户机的信息?我这不但能接收,还能全部转发,我这问题就是能向所有机子发送信息却不能对单个发送信息~~还是等高人来找下问题
发表于 2009-9-23 13:42:00 | 显示全部楼层
辛苦了
 楼主| 发表于 2009-9-23 14:18:18 | 显示全部楼层
本帖最后由 jycel 于 2009-9-23 14:24 编辑
辛苦了
kn007 发表于 2009-9-23 13:42

我还以为你来帮我解决问题了呢
问题一直未解决!找帽子呢~~大忙人
 楼主| 发表于 2009-9-24 10:00:44 | 显示全部楼层
哈哈!今早做卫生时灵感一下就来了随时都把没解决的问题挂到在~~~
答案就在以前的代码中~~
终于搞定了
发表于 2009-9-27 04:45:30 | 显示全部楼层
恩。。。。你这个是对的  我原以为一个端口只能连一个client,刚测试了一个端口2个client 也行 我要重写了 n你那个connected的数组有点难看懂 我也要写这一步,写好那步就差不多了。。。 我原来写的一个是服务端跟客户端反过来 让客户端开个端口 服务端直接连的
发表于 2009-9-27 08:34:11 | 显示全部楼层
呵呵,学习一下。。
 楼主| 发表于 2009-9-27 10:13:42 | 显示全部楼层

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2009-9-28 01:55:40 | 显示全部楼层
这是我写好的 accept   and  recv     ,$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
            我写不出你那么复杂的数组。。。。
发表于 2009-9-28 07:50:34 | 显示全部楼层
 楼主| 发表于 2009-9-28 22:33:55 | 显示全部楼层
局域网的已经搞定了,是以昵称显示在线用户,但是用于外网的话会产生二个IP很郁闷一直搞不定,外网直接用IP来显示就不会出错,
下载地址:http://jycel.ys168.com
您需要登录后才可以回帖 登录 | 加入

本版积分规则

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

GMT+8, 2024-9-29 06:43 , Processed in 0.114559 second(s), 24 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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