找回密码
 加入
搜索
查看: 4771|回复: 21

[已解决]TCP命令新问题

[复制链接]
发表于 2009-4-22 16:20:30 | 显示全部楼层 |阅读模式
本帖最后由 jycel 于 2009-4-23 10:32 编辑

TCPRecv和TCPSend 做局域网信息传递,先前,用TCP时,二台机子,服务端和客户端可以互相发送,但多个客户端发送时,服务端只能接收第一个客户端信息,参照了下论坛的贴子,实现了接收多个客户端信息,但服务端无法回复!请问这该怎么来写?
注:我的思路是这样的,客户端发送消息到服务端,服务端根据客户机的IP来回复信息并且记录下当前IP到配置文件以便显示到GUI上面(客户机肯定分布在多台机子),然后选择要回复的IP来回复!具体怎么写请指点下!
发觉论坛改版后,发代码看起很不方便,就放附件中了
顺便上传了UDP的,问题同样!
上传下图片:

本帖子中包含更多资源

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

×

评分

参与人数 1金钱 +10 贡献 +5 收起 理由
lynfr8 + 10 + 5 原创内容,感谢你对论坛的支持;希望继续发 ...

查看全部评分

 楼主| 发表于 2009-4-22 18:26:26 | 显示全部楼层
一直在努力研究!技术有限,还得期待高手指点!
发表于 2009-4-22 20:37:49 | 显示全部楼层
用一个二维数组存放Socket与IP的对应关系,因为通信是用Socket而不是IP的。根据输入IP检索对应Socket,再向它发送。
 楼主| 发表于 2009-4-22 23:15:29 | 显示全部楼层
加了一个输入IP回复,服务端一直发不出去消息,不知道问题在那儿,现在只是在测试回复一个,其实与选择回复都一样效果了,一个能做到其它都能做到!

#AutoIt3Wrapper_Icon=ico.ico                           ;需要使用的图标(路径)名称
#AutoIt3Wrapper_OutFile=TCP服务端.exe                        ;目标 exe/a3x 文件名.
HotKeySet("{ENTER}","_send")
#include <GUIConstants.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
;$File="配置.ini"
;$ip=IniRead($File,"配置","服务器地址","")
$Dll = DllOpen(@ScriptDir & "\Skin\SkinCrafterDll.dll")
$skinTemp=iniread($File,"配置","皮肤","")
$skin="\skin\"&$skinTemp
Opt("GUIOnEventMode", 1)
#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("【飛翔網絡】局域网聊天软件 Server", 291, 208, 192, 114)
_SkinGUI(@ScriptDir & "\Skin\SkinCrafterDll.dll", @ScriptDir & "\"&$skin, $Form1)
GUISetOnEvent($GUI_EVENT_CLOSE, "_ext")
$Edit0 = GUICtrlCreateEdit("历史消息:"&"本机用户名→"&@ComputerName, 8, 8, 273, 18, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_CLIPSIBLINGS,$ES_READONLY))
GUICtrlCreateLabel("请输入IP",8,152)
$Edit1 = GUICtrlCreateEdit("", 8, 28, 273, 116, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_CLIPSIBLINGS,$ES_READONLY,$ws_VSCROLL))
$Edit3 = GUICtrlCreateInput("", 63,148,30,20,$ES_NUMBER );IP地址
$Edit2 = GUICtrlCreateEdit("", 92, 148, 189, 20, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_CLIPSIBLINGS))
GUICtrlSetData(-1, "")
$Button1 = GUICtrlCreateButton("发送[&Enter]", 8, 176, 113, 25, 0)
GUICtrlSetOnEvent(-1, "_send")
$Button2 = GUICtrlCreateButton("退出[&Esc]", 168, 176, 113, 25, 0)
GUICtrlSetOnEvent(-1, "_ext")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

;----------------------------------
Global $aConnected[1] = [0]
TCPStartUp()

$MainSocket = TCPListen(@IPAddress1, 65432,  100 ) 
If $MainSocket = -1 Then  Exit    ;创建监听不成功就退出

$Socket = -1


While 1
        
                Accept()
                Recv()
                Sleep(100)
Wend

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

Func _send()
$szData = @ComputerName&">"&GUICtrlRead($Edit2)
$bj="本机发送:"&GUICtrlRead($Edit2)
   $Edit=GUICtrlRead($Edit2)
        If $Edit = "" Then 
                MsgBox(0,"提示","消息不能为空!",1)  ;延时5秒自动退出
                        Else
                                $MainSocket = TCPListen(@IPAddress1, 65432,  100 ) 
                                $fs=TCPConnect($ip,65432) 
                                $iph="192.168.0."&guictrlread($Edit3);读取IP号,用来做回复客户机用!
                                $szData1 = StringToBinary($szData, 4)
                TCPSend($Socket,$szData1)   ;发送信息
                                GUICtrlSetData($edit1, $bj& @CRLF &GUICtrlRead($edit1))
                                GUICtrlSetData($Edit2, "")
        EndIf
        If @error Then MsgBox(0,"提示","消息发送失败!",1)  ;延时5秒自动退出
EndFunc
Func _SkinGUI($SkincrafterDll, $SkincrafterSkin, $Handle)
        $Dll = DllOpen($SkincrafterDll)
        DllCall($Dll, "int:cdecl", "InitLicenKeys", "wstr", "1", "wstr", "", "wstr", "1@1.com", "wstr", "1")
        DllCall($Dll, "int:cdecl", "InitDecoration", "int", 1)
        DllCall($Dll, "int:cdecl", "LoadSkinFromFile", "wstr", $SkincrafterSkin)
        DllCall($Dll, "int:cdecl", "DecorateAs", "int", $Handle, "int", 25)
        DllCall($Dll, "int:cdecl", "ApplySkin")
EndFunc   ;==>_SkinGUI
Func Accept()
        $ConnectedSocket = TCPAccept($MainSocket)
        If $ConnectedSocket <> -1 Then
                _ArrayAdd($aConnected, $ConnectedSocket)
                $aConnected[0] += 1
        EndIf
        Return
EndFunc
 
Func Recv()
        $i = 1
        While $i <= UBound($aConnected) - 1
                $sRecv = TCPRecv($aConnected[$i], 2048, 1);256)
                If @error Then   ; 客户端已关闭
                        _ArrayDelete($aConnected, $i)
                        $aConnected[0] -= 1
                ElseIf $sRecv = "" Then   ; 客户端未发送数据,继续处理下一客户端
                        $i += 1
                                        Else
                                                $srecv = BinaryToString($srecv, 4)
                                                GUICtrlSetData($edit1, $srecv & @CRLF & GUICtrlRead($edit1))                       
                                           ; 接收数据处理。完成后TCPCloseSocket,然后删除数组单元并将 $aConnected[0] -= 1
 
                EndIf
        WEnd
        Return
EndFunc
发表于 2009-4-22 23:19:01 | 显示全部楼层
呵呵,我想等现成的。。
C/S结构的问题,坛子里玩的人不太多,知道破帽子好象一直有兴趣,三恨也有研究的
 楼主| 发表于 2009-4-22 23:25:10 | 显示全部楼层
本帖最后由 jycel 于 2009-4-22 23:26 编辑

现成不好等啊!搞了了二天了,先是一徘徊倒底用TCP来做还是UDP,TCP能实现互发了,但不能用多个客户端,现在能用多个客户端了,却服务端不能向客户端发!用UDP呢也同样效果,都能向服务端发消息,却无法回!
发表于 2009-4-22 23:42:58 | 显示全部楼层
5# jycel


简单看了一下,晕了。。。
TCPSend($Socket,$szData1),而$Socket = -1,能发出才有鬼了。。。TCPListen是开始端口侦听,代码里出现了2次。。。
感觉你对网络通信还是不熟悉啊。请注意,网络通信中,IP地址只用于连接,连接成功后就不用了,这时的通信是用连接时产生的Socket,发送/接收数据就是写和读Socket。我们可以在一台机器上运行多个客户端而不会相互影响,就是因为虽然IP地址甚至端口是同一个,但各自的Socket是不相同的。
发表于 2009-4-22 23:48:03 | 显示全部楼层
专业味道啊。。
唉,我这非计算机专业出身,差距啊差距。。
发表于 2009-4-23 00:03:35 | 显示全部楼层
请仔细看一下帮助文件里TCPRecv和TCPSend所带的示例。
我简单说一下au3里的网络通信过程。

服务端:
TCPStartup启动TCP
TCPListen使用IP和端口开始侦听,由此产生一个MainSocket
TCPAccept轮询MainSocket,等待客户端连接。如果返回不是-1,说明一个有效客户端已经连接,返回值就是这个客户端的连接Socket。

客户端:
TCPStartup启动TCP
TCPConnect使用IP和端口接连到服务端。如果返回不是-1,说明服务端连接成功,返回值就是当前的连接Socket。

连接成功后:
发送/接收数据:TCPSend/TCPRecv各自的连接Socket,如果返回@error为真,说明对方已断开连接。注意TCPRecv会返回空值,说明对方尚未发送数据或数据未到达。

至于如何从Socket获得对方IP地址,示例里的SocketToIP函数就是用来转换的。注意这个IP并不在通信过程中起作用,示例里是用在服务端窗口显示数据由谁发送。
 楼主| 发表于 2009-4-23 00:15:51 | 显示全部楼层
帮助中仅是单向发送!道理都弄明白了,转换成互发后,双方同时又是接收端又是发送端!试来试去,要么能互发,要么不能接收多个客户端
发表于 2009-4-23 03:52:52 | 显示全部楼层
总算改好了。。。测试通过。
几点说明:
提示不能用MsgBox,因为它会暂停脚本运行,可能影响别的客户端连接和数据发送。我另建了一个Label控件,提示都放那里了。
GUI不需要事件模式。事件模式下循环里需要加Sleep,否则CPU占用太高。但Sleep也会暂停脚本。像这种以GUI为中心的程序,根本不需要用到事件模式。
发送和接收的消息中,机器标识不使用计算机名,仅使用IP地址。因为计算机名在某种程度上也算是网络隐私。
一些细节我就不动了,你自己慢慢完善吧。

最后的最后,你居然敢用HotKeySet("{ENTER}","_send"),我的神啊。。。
HotKeySet设置的是全局热键,你这么一弄,只要你的程序开着,其他程序都别想接收到Enter键了。我开了服务端再开客户端,就搞不懂为什么服务端可以用Enter直接发送,客户端怎么不行?还以为Win发神经了,重启了又检查别的程序,足足折腾半个小时。

本帖子中包含更多资源

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

×
 楼主| 发表于 2009-4-23 09:14:42 | 显示全部楼层
太感谢了!昨晚弄太晚,今天上班都迟到了!马上试下!
发表于 2009-6-15 11:02:50 | 显示全部楼层
不清楚
发表于 2009-6-15 11:43:01 | 显示全部楼层
留名学习、、
发表于 2009-6-15 15:39:46 | 显示全部楼层
呵呵  对于通讯方面我是一片空白,留个记号  以后用的着了慢慢学习
您需要登录后才可以回帖 登录 | 加入

本版积分规则

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

GMT+8, 2024-10-3 00:31 , Processed in 0.077769 second(s), 21 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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