[已解决]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
如果没有多的电脑,测试时可以直接向本机IP发送即可 本帖最后由 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
我看看哈..我也正在写这个网吧用的...我那个如果有人连接的话 服务端会自动跳到那个人的IP 并变颜色 本来开始用的时候服务端 CPU只有5不到的 后来工作机换了下系统CPU就跳上去了 现在必须重些了 你写的这个不行啊 TCP连接只能1个端口对一个client不能一个端口接受很多client的数据你这个顶多是1对1的而且还有出错... 楼上测试我的代码没有?服务端怎么可能无法接收多个客户机的信息?我这不但能接收,还能全部转发,我这问题就是能向所有机子发送信息却不能对单个发送信息~~还是等高人来找下问题 辛苦了 本帖最后由 jycel 于 2009-9-23 14:24 编辑
辛苦了
kn007 发表于 2009-9-23 13:42 http://www.autoitx.com/images/common/back.gif
:face (13): 我还以为你来帮我解决问题了呢
:face (36):问题一直未解决!找帽子呢~~大忙人 哈哈!今早做卫生时灵感一下就来了:face (13):随时都把没解决的问题挂到在~~~
答案就在以前的代码中~~
终于搞定了 恩。。。。你这个是对的我原以为一个端口只能连一个client,刚测试了一个端口2个client 也行 我要重写了 n你那个connected的数组有点难看懂 我也要写这一步,写好那步就差不多了。。。 我原来写的一个是服务端跟客户端反过来 让客户端开个端口 服务端直接连的 呵呵,学习一下。。
目前测试如上图,我把IP转换成了昵称后,有点问题就是上线没问题,下线后,在线用户客户端列表中不清除下线用户!估计那儿判断有问题,还在测试中 这是我写好的 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
我写不出你那么复杂的数组。。。。 http://b24.photo.store.qq.com/http_imgload.cgi?/rurl4_b=4b8cfd8d67ec1bb3796bc32410b8367360f6ff2edfd88acdb6be8949431dcc4848e7ba7777a4ea782a501bc9b9433800a038c41b91ee6d686b739ca81654d07582432bbd52806349b2d0bb06809344dc60bde91d 局域网的已经搞定了,是以昵称显示在线用户,但是用于外网的话会产生二个IP很郁闷一直搞不定,外网直接用IP来显示就不会出错,
下载地址:http://jycel.ys168.com
页:
[1]
2