找回密码
 加入
搜索
查看: 30669|回复: 33

[网络通信] TCP连接怎么实现外网连接

 火... [复制链接]
发表于 2011-5-18 14:43:59 | 显示全部楼层 |阅读模式
悬赏200金钱已解决
本帖最后由 tryhi 于 2011-5-18 23:03 编辑

这里有一个很好的例子,在局域网测试通过,但用来连接外网,好像就不行了
http://www.autoitx.com/forum.php ... ght=%2B%CD%E2%CD%F8

帖子是收费贴,我把代码上传了,希望作者不要介意。

主要问题在于TCP怎么用外网连接,只需要服务端的外网IP地址就能连接么?





客户端
;~ by yeqing880
TCPStartUp()
AdlibRegister ("Mem",3000)
Global $Socket
 
conn()
 
 
While 1
        
        $sRecv = TCPRecv($Socket, 2048, 1)
        If @error Then 
        AdlibUnRegister ("sendx")
        conn()
    EndIf
    If $sRecv <> "" And $sRecv = "shutdown" Then Exit
        
WEnd
 
Func Sendx()
        TCPSend ($Socket,StringToBinary("online",4))
EndFunc
 
Func conn()
Do
Sleep (1000)
$Socket = TCPConnect("192.168.1.71",1313) 
Until $Socket <> -1
AdlibRegister ("sendx",5000)
EndFunc
 
Func Mem()
        Local $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, _
        'int', False, 'int', @AutoItPID)
        Local $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', $ai_Handle[0])
        DllCall("kernel32.dll" , 'int', 'CloseHandle', 'int', $ai_Handle[0])
EndFunc

服务端
;~ by yeqing880
#include "TCP.au3"
#include <date.au3>
#include <Array.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiStatusBar.au3>
#include <ListViewConstants.au3>
#include <WindowsConstants.au3>
#Include <GuiListView.au3>
 
Opt("GUIOnEventMode", 1)
Opt("TrayMenuMode",3)
Opt("TrayOnEventMode",1)
 
$displayitem    = TrayCreateItem("退出")
TrayItemSetOnEvent($displayitem,"_exit")
 
Global $chaoshi = "",$szid = 0
 
Global $chaoshitime = 30 ;根据实际情况设置超时时间
 
Global $timeset = 1000 ;根据实际情况设置timer调用时间
 
Dim $lianjie[1][3]
 
 $hServer = _TCP_Server_Create("1313","192.168.1.71")
_TCP_RegisterEvent($hServer, $TCP_NEWCLIENT, "NewClient")
_TCP_RegisterEvent($hServer, $TCP_DISCONNECT, "Disconnect")
_TCP_RegisterEvent($hServer, $TCP_RECEIVE, "rev")
 
 
$Form1 = GUICreate("Form1", 620, 562,150,100)
GUISetOnEvent($GUI_EVENT_CLOSE,"gui")
$ListView1 = GUICtrlCreateListView("Socket|IP地址", 200, 0, 419, 451)
$Menu = GUICtrlCreateContextMenu($ListView1)
$exitall= GUICtrlCreateMenuItem("全部退出",$Menu, 1)
GUICtrlSetOnEvent(-1, "shutdown2")
$Edit1 = GUICtrlCreateEdit("", 0, 0, 198, 451, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_VSCROLL))
$StatusBar1 = _GUICtrlStatusBar_Create($Form1)
Dim $StatusBar1_PartsWidth[3] = [150, 250,400]
_GUICtrlStatusBar_SetParts($StatusBar1, $StatusBar1_PartsWidth)
_GUICtrlStatusBar_SetText($StatusBar1, "服务器建立成功,监听中....", 0)
_GUICtrlStatusBar_SetText($StatusBar1, "当前在线数0", 1)
 
$Edit2 = GUICtrlCreateEdit("", 0, 452, 619, 89, BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN,$WS_VSCROLL))
GUISetState(@SW_SHOW)
 
$Form2 = GUICreate("数组", 411, 303, 154+620,100)
$ListView2 = GUICtrlCreateListView("ID|Socket|IP|TIME", 0, 0, 410, 302)
GUISetState(@SW_SHOW)
 
$Timer = DllCallbackRegister("check", "int", "hwnd;uint;uint;dword")
$TimerDLL = DllCall("user32.dll", "uint", "SetTimer", "hwnd", 0, "uint", 0, "int", $timeset, "ptr", DllCallbackGetPtr($Timer))
$Timer2 = DllCallbackRegister("check2", "int", "hwnd;uint;uint;dword")
$TimerDLL2 = DllCall("user32.dll", "uint", "SetTimer", "hwnd", 0, "uint", 0, "int", 1000, "ptr", DllCallbackGetPtr($Timer2))
 
 
While 1
        Sleep (100000)
WEnd
 
Func NewClient($hSocket, $iError)
ReDim $lianjie[UBound($lianjie) + 1][3]
$lianjie[0][0] += 1     
$lianjie[UBound($lianjie) - 1][0] = $hSocket
$lianjie[UBound($lianjie) - 1][1] = _TCP_Server_ClientIP($hSocket)
$lianjie[UBound($lianjie) - 1][2] = $chaoshitime
GUICtrlSetData ($Edit1,GUICtrlRead($edit1)&_TCP_Server_ClientIP($hSocket)&"/"&$hSocket&" 连接!"&@CRLF)
GUICtrlCreateListViewItem ($hSocket&"|"&_TCP_Server_ClientIP($hSocket),$listview1)
getonling()
EndFunc
 
Func rev($hSocket, $sReceived, $iError)
If $sReceived = "online" Then 
$lianjie[_ArraySearch ($lianjie,$hSocket, 1, 0, 0, 0, 1)][2] = $chaoshitime
EndIf
EndFunc
 
Func Disconnect($hSocket, $iError)
If $hSocket = $chaoshi  Then 
$chaoshi = ""
Return
Else
$s = _ArraySearch ($lianjie,$hSocket, 1, 0, 0, 0, 1)
GUICtrlSetData($Edit1,GUICtrlRead($edit1)&$lianjie[$s][1]&"/"&$lianjie[$s][0]&" 离线(退出)!"&@CRLF)
_GUICtrlListView_DeleteItem ($ListView1,_GUICtrlListView_FindInText($ListView1, $lianjie[$s][0]))               
_ArrayDelete($lianjie,$s)
$lianjie[0][0] -= 1     
getonling()
EndIf   
EndFunc
 
Func Shutdown2()
For $s = 1 To UBound($lianjie) - 1
        TCPSend($lianjie[$s][0],"shutdown")
Next
 
EndFunc
 
Func check($hWnd, $uiMsg, $idEvent, $dwTime)
        Local $s = 1
        $begin = TimerInit()
        While $s <=  UBound($lianjie) - 1
                If $lianjie[$s][2] <= 0 Then 
                $chaoshi = $lianjie[$s][0]
                _TCP_Server_DisconnectClient($lianjie[$s][0])
                GUICtrlSetData($Edit1,GUICtrlRead($edit1)&$lianjie[$s][1]&"/"&$lianjie[$s][0]&" 离线(超时)!"&@CRLF)
        _GUICtrlListView_DeleteItem ($ListView1,_GUICtrlListView_FindInText($ListView1, $lianjie[$s][0]))               
        _ArrayDelete($lianjie,$s)
                $lianjie[0][0] -= 1             
                getonling()
                GUICtrlSetData($Edit2,"超时检测完成,耗时大约"&Round (TimerDiff($begin),2)&"秒 当前时间:"&_Now()&@CRLF&GUICtrlRead($Edit2))
                Return
            Else
                If $lianjie[$s][0] <> "del" Then $lianjie[$s][2] -= 1
            EndIf
        $s += 1
    WEnd
    GUICtrlSetData($Edit2,"超时检测完成,耗时大约"&Round (TimerDiff($begin),2)&"秒 当前时间:"&_Now()&@CRLF&GUICtrlRead($Edit2))
 
EndFunc
 
Func check2($hWnd, $uiMsg, $idEvent, $dwTime)
 
GUICtrlSendMsg($ListView2, $LVM_DELETEALLITEMS, 0, 0)
GUICtrlCreateListViewItem ("0||||",$ListView2)
For $s = 1 To UBound($lianjie) - 1
        
GUICtrlCreateListViewItem($s&"|"&$lianjie[$s][0]&"|"&$lianjie[$s][1]&"|"&$lianjie[$s][2],$ListView2)
        
Next
 
 
EndFunc
 
Func getonling()
_GUICtrlStatusBar_SetText($StatusBar1, "当前在线数"&UBound($lianjie)-1, 1)
EndFunc
 
Func gui()
        Switch @GUI_CtrlId
                Case $GUI_EVENT_CLOSE
                        _exit()
                        
        EndSwitch
EndFunc
 
Func _exit()
DllCallbackFree($Timer)
Sleep (1000)
_TCP_Server_Stop()
Exit
EndFunc


需要用到这个UDF




续:回复都很精辟,不知选哪条
附件: 您需要 登录 才可以下载或查看,没有账号?加入

最佳答案

查看完整内容

这样的连接方式可以采用另外的办法来完成。 只让客户端单方面获取服务器端数据。不要发回数据。 方法是: 1.服务器端创建监听接口。 路由映射出去。 2.客户机启动,连接服务器端口,发送过去“我上线了” 3.服务器端接收到“客户机上线消息”,则根据该客户端标志(这个标志可以在发送我上线了的时候一并发送过来),在本地创建一个以客户机标志命名的文件,然后,本地创建HTTP服务器,可以用傻瓜HTTP、Netbox这样的工具来架设。 然后 ...
发表于 2011-5-18 14:44:00 | 显示全部楼层
这样的连接方式可以采用另外的办法来完成。 只让客户端单方面获取服务器端数据。不要发回数据。 方法是:
1.服务器端创建监听接口。 路由映射出去。
2.客户机启动,连接服务器端口,发送过去“我上线了”
3.服务器端接收到“客户机上线消息”,则根据该客户端标志(这个标志可以在发送我上线了的时候一并发送过来),在本地创建一个以客户机标志命名的文件,然后,本地创建HTTP服务器,可以用傻瓜HTTP、Netbox这样的工具来架设。 然后,路由器再映射80端口到本机80端口。
4.客户机启动发送 我上线了消息后,创建一个定时器,不断的读取服务器80端口,读取发送出去的标志为名字的htm或txt文件。 读取后分析其中内容即可获得服务器对自己做了什么响应。

这样,客户机只需要访问服务器,不需要自身映射就可以完成单方面获取注册信息等数据。 非常方便。

评分

参与人数 1贡献 +5 收起 理由
tryhi + 5 学习了

查看全部评分

发表于 2011-5-18 19:13:29 | 显示全部楼层
直接把源码贴出来吧,没钱下载啊

评分

参与人数 1金钱 +20 收起 理由
tryhi + 20 十分感谢您的关注与顶贴

查看全部评分

 楼主| 发表于 2011-5-18 19:17:00 | 显示全部楼层
回复 2# cnmini

感谢你的关注,因为提问区下载源码不要钱的,而且源码有点长,看来我还是贴出来好点
发表于 2011-5-18 19:24:01 | 显示全部楼层
你服务器端在外网还是在内网? 需要在路由上映射

评分

参与人数 1金钱 +20 收起 理由
tryhi + 20 十分感谢疯前辈关注。

查看全部评分

 楼主| 发表于 2011-5-18 19:30:36 | 显示全部楼层
回复 4# lanfengc

服务端在外网,我就是搞不清楚,仅通过一个外网IP是否真的可以连接。

我看里面有一个IP,应该说服务端改成服务端本机的外网IP,客户端里面的IP也改成服务端机子的外网IP应该就能连接得上,我是这样理解的,不知哪里出问题
发表于 2011-5-18 19:42:37 | 显示全部楼层
通讯是这样的。AU3创建TCP连接的时候,不可以在同一端口发送和接受数据(这是我的一点看法, 如果不对,请指正),比如你的网络环境是这样的, 服务器端所在的网络为A, 客户机所在的网络为B, 客户机要访问服务器上的数据。 首先要经过网络B的路由器,然后一级一级路由到A网络,经由A网络路由器到服务器。 然后服务器接受到你发送过去的数据,要再开一个端口发送回数据。 此时,服务器和客户机就对调了过来了。服务器变成了客户机,客户机变成了服务器,如果本地客户机没有对外映射接受数据的端口,则服务器发回数据的时候,其实访问的是网络B路由器的端口,如果网络B的路由器对客户机的接受端口没有映射,则数据不可达。 就会造成两个机器无法通讯。  明白了吗?

评分

参与人数 1金钱 +20 贡献 +5 收起 理由
tryhi + 20 + 5

查看全部评分

发表于 2011-5-18 19:45:38 | 显示全部楼层
我个人看法:
因服务端与客户端有交互,走外网的话,那必须双方的身份是公网IP!但实际情况一般是:双方均在各自的局域网中。这样就需要在双方路由器上做是映射。并且在脚本中指定对方公网IP及端口。
似乎这是一个网络通讯的问题,呵呵,不是脚本本身的问题。。。。
希望有牛人多多指教!

评分

参与人数 1金钱 +20 收起 理由
tryhi + 20 感谢关注

查看全部评分

 楼主| 发表于 2011-5-18 19:50:09 | 显示全部楼层
回复 7# boyhong

如果服务端本身没通过局域网而直接通过MODE直接上网呢?
 楼主| 发表于 2011-5-18 19:57:37 | 显示全部楼层
通讯是这样的。AU3创建TCP连接的时候,不可以在同一端口发送和接受数据(这是我的一点看法, 如果不对,请指 ...
lanfengc 发表于 2011-5-18 19:42


那如果服务端运行在一台服务器上,这样也连接不了么?

这样的话,好像普通情况下好像都是无法通讯的
发表于 2011-5-18 20:05:13 | 显示全部楼层
不管你运行在什么机器上。  通过modem上网的环境可以。 因为你本身就是个公网IP, 但是这个公网IP会变动。 需要希网域名来解析。  运行在服务器上,如果是公网IP的服务器,可以。 内网服务器通过映射发布的服务器,还是不行。

评分

参与人数 1金钱 +20 贡献 +5 收起 理由
tryhi + 20 + 5 哇,确实是这样哦。真的可以

查看全部评分

 楼主| 发表于 2011-5-18 20:53:03 | 显示全部楼层
不管你运行在什么机器上。  通过modem上网的环境可以。 因为你本身就是个公网IP, 但是这个公网IP会变动。  ...
lanfengc 发表于 2011-5-18 20:05


哇,确实是这样哦,通过MODEM的机子就可以,之前找了几人试,原来都是用路由的
发表于 2011-5-18 21:44:52 | 显示全部楼层
此问题论坛一早已讨论过
http://www.autoitx.com/forum.php?mod=viewthread&tid=5455
作为高级会员,请学会搜索

评分

参与人数 1金钱 +20 收起 理由
tryhi + 20 感谢版主指点

查看全部评分

发表于 2011-5-18 22:18:24 | 显示全部楼层
我也覺得是兩方面  路由器設定問題吧......內網可以通  外網理論上就可以通才對呀

评分

参与人数 1金钱 +10 贡献 +3 收起 理由
tryhi + 10 + 3 确实,直连上网的可以通

查看全部评分

 楼主| 发表于 2011-5-18 22:45:34 | 显示全部楼层
此问题论坛一早已讨论过

作为高级会员,请学会搜索
ceoguang 发表于 2011-5-18 21:44


确实,我也是搜遍了都没找到才来问的。

    不过没关注UDP

你该去研究一下什么叫端口映射,什么叫反向链接.

确实,我该自己研究一下,感谢指点
您需要登录后才可以回帖 登录 | 加入

本版积分规则

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

GMT+8, 2024-5-13 02:19 , Processed in 0.088798 second(s), 24 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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