1.执行客户端发来的SQL命令并把结果返回;
2.同时有多个客户端连接;
3.服务端在NAT之后,客户端可能在局域网内也可能在外网或不同NAT之后(只考虑 Cone NAT)我自己的思路是:
服务端创建一个监听线程监听端口如2000,当收到客户端请求后,创建一个新的线程,其UDP的远程地址和端口为刚才监听线程收到的地址和端口,然后再和客户端进行通信做相关处理。当客户端和服务端在局域网内时一切都正常,当服务端在NAT之后,客户端直接通过ADSL拨号通信也正常,但是当客户端也在NAT之后时,服务端收到请求后直接回复没有问题,但是创建了新的线程后,新的线程发送的数据客户端无法收到。
不知道问题在哪里,困扰了很久,请高人指点一下,谢谢!
解决方案 »
- 看看下面的代码
- 如何调试其他电脑的应用程序(局域网),急急急!!!!!在线等!!!
- 如何使Windows2000具有XP的效果
- 怎样实现象photoshop那样图片选中后周围出现选种边框,并可调图象大小
- 电影来了,各位休息一下吧
- update语句请教!
- 如何再生成由QUERY1生成数据的第N条到第M条记录?
- 请问如何在Delphi中实现 AutoComplete(自动完成) 的功能?急!急!急!
- 问大家一个问题,DATASource是不是连接ACCESS表的数据库,如果是连接SQL的要用哪个呢?
- delphi2010开发的程序,本地没问题,但到别的机子上提示错误,怎么回事?
- 怎么用Delphi画方格图啊?大哥哥们帮忙啊,急死人了
- RasGetCredentials报632错也就是ERROR_INVALID_SIZE,请大侠帮忙看
ABinding: TIdSocketHandle); 看你用的什么控件 ,如果 是INDY的,它本身就是多线程的,不用你再去创建新的线程。如果你要回复,直接用 ABinding 发回复数据就可以了。
端口号子,然后将任务对象放到一个任务列表A中就OK系统中存在一个任务处理线程,负责从任务列表A中取出任务,处理,如果任务实在太多,可以多创建几个处理线程,
但不要太多.任务处理结束后就将任务和任务结果从任务列表A中放到任务列表B中.系统中存在一个任务发送线程,负责从任务列表B中取出结果发送出去.可以多创建几个任务发送线程.任务列表A,任务列表B 是两个任务缓冲区,如果超出设定值,可以让用户暂缓发送.对于你的需求,接收的都是些SQL语句,任务列表A的压力应该不大.主要在于结果的返回.如果用户了*来查询的话
会有大量的数量要返回.你可以将一些SQL的查询结果保存下来,当新的SQL语句执行时检查一下是否刚查询过,这样可以快速的返回结果.
你的方法确实是一种办法,如果我的方法行不通只好按这种任务队列方式了。
我主要想通过类似P2P的方式,每个客户端的每个请求都和服务端建立一个独立的UDP socket,在这个独立的UDP socket 连接中进行相应处理。
2.看看是哪个用户发过来的SQL命令
3.执行SQL语句
4.把结果发送给那个用户
我前面说的SQL语句,其实不止是SQL文本,还有些参数可能有图片之类的,需要分包发送,服务端也要进行组包,中间还要判断丢包超时等情况。不过这都不是问题,关键我现在的程序,在局域网内运行正常,可以开很多客户端,同一机器上也可以开多个客户端。
我的服务端在内网,在路由上也做了监听端口的映射,远程客户端如果是ADSL拨号也运行正常,如果是远程客户端也在内网就不能通信了。估计是穿NAT问题,如果有办法解决最好不要用UDP中转,不是不能用中转的方法,只是对穿NAT没有研究过想借此学习一下,网上穿NAT的文章翻来覆去就那一篇文章,下载了一些P2P的源码也看了,那些源码跟我遇到的问题一样,哪位老牛真正的实现了P2P,请不吝赐教。
Symmetric nat 过不去 (DLink DI504)
其他两种 nat 暂时没有设备
处理端为:192.168.0.1:2000(内网地址) 222.10.10.10:2000(外网地址)
中转端为:192.168.0.2:2001(内网地址) 222.10.10.10:2001(外网地址)
客户端为:192.168.1.1:1000(内网地址) 117.101.10.10:12345(外网地址)1.服务端开一个UDP的监听线程和中转线程,如监听端口 2000中转端口2001,在路由上已做映射;
2.服务端收到客户端请求后,创建子线程,子线程回复客户端(除Symmetric nat客户端以外,都可以收到回复并可与之通信)
注:包头不是中转包标志
3.客户端收到回复后与服务端子线程进行通信(上传命令包、等待执行、接收结果等)4.如果客户端收不到服务端子线程的回复,说明在 Symmetric nat之后
a.客户端发送包到中转端口,包头添加处理服务器的地址和端口和中转标志
如:
TTranPack = record
TranMark : integer;
IP : LongInt;
Port : word;
end;
b.中转服务端收到客户端包后,将包中的IP和Port改成客户端外网的IP和Port,然后按包中的地址将包发送出去。
如:中转端收到客户端117.101.10.10:12345的包,包内IP为222.10.10.10 Port:2000
中转端修改包内IP由222.10.10.10改为117.101.10.10端口由2000改为123456
然后将包发送到:222.10.10.10:2000(如中转和处理端都在内网,路由要支持回环,否则建立一个对应表) c.处理服务器判断为中转包,处理完后包里添加中转标志,地址和端口与收到包里的地址端口相同,然后发给中转服务器。
如:收到中转端 222.10.10.10:2001的包,包内IP为:117.101.10.10端口为123456
处理完后,包里的地址仍然为IP为:117.101.10.10端口为123456,
然后将包发送到:222.10.10.10:2001
d.中转服务端收到处理端的包后,将包里的IP和Port换成收包的IP和Port,然后按包里的地址发送出去。
处理过程同B 中转端没有做队列处理,因为我的中转端和处理端在一个内网,中转速度应该很快,而且通信过程采用一问一答的方式,到底会不会丢包只有通过一定量客户端测试才行。
ZyxIp 的方法也不错,服务端只需要一个端口,而且不需要中转,没有Nat的限制,但是那个队列方式编程复杂度太高,没有一问一答来的简单(个人认为)
不知有没有对Symmetric nat的处理的好方法呢?
再等两天看看,就结贴散分了~
INDY9使用了IOCP,数据到达通知,灰常的方便!
所以,基本上我可以认为你有了一个UDP端口的服务器(端口映射也是一样),SO你没有必要创建一个子线程去应答。
INDY为你做好了一个应答机制。基本上如果你有能力使用API完成到现在这个程度,了解和使用INDY也就是10分钟的事情。另外你需要注意的一点就是:数据包的大小,我注意到了你的测试环境是局域网,局域网或者宽带环境MTU是相对宽松的,你发一个N大的包都可以顺利接受
在一个ADSL拨号的情况下,是有MTU值的限制的一般ADSL为1500
所以建议你的每个数据包不要大于1458(UDP传输的时候42个IP包头也算)
另外要考虑的就是UDP的不稳定性,相信你都做到了。
1.客户端发送请求
2.服务端回应并要求客户端发送数据包头(指要提交的包的总大小,需要分多少次发送)
3.客户端发送包头
4.服务端收到包头,分配缓冲区,并要求客户端发送数据包(N个包)
5.服务端收取数据包,并检查缺少的包,要求重发(一直重复 4,5步骤直到收取所有数据包)
6.分解数据包,将SQL语句和参数分解开,调用SQL执行过程(SQL执行的时间可能比较长,因此用线程方式,能够让主线程继续相应客户端命令)
7.客户端等待服务端执行SQL查询,每隔几秒询问一次是否查询执行完成(所以增加此询问过程,避免客户端因特殊情况无限等待,每次执行的SQL时间可能不一致不能设置固定等待时间)
8.服务端执行完SQL查询后,将结果放到缓冲区里,将结果大小和需要多少次发送数据发给客户端
9.客户端收到包头后分配缓冲区,请求服务端发送数据包
10.服务端发送数据包
11.客户端收取数据包,并要求重发丢失的包,重复10,11步骤,直到数据包收取完整。
12.结束在以上过程中,每次的应答都要有超时判断和按指定次数重试,超过指定重试次数后返回错误。当有多个客户端时,服务端相应代码就会变的很复杂,估计处理调试都是麻烦。而且,我准备将文件传输等其他功能也添加进去,增加功能时只需要每次按照相应流程写个相应的线程就OK了,如同写单个客户端和服务器通讯一样,不影响到其他功能。
个人愚见,可能哪位大侠有更好的方法,我就当抛砖引玉了,共同学习,共同进步!
1、报文类型
2、报文参数1
3、报文参数2
4、后续数据长度
5、总数据长度
6、文本信息1(固定长度,用于放置文件名之类)
7、文本信息2(固定长度,用于放置验证码之类)建一个固定长度的buffer,把报文头和数据内容放入这个buffer,sendto....如果在指定时间没有收到“应答”报文,则继续sendtorecvfrom之后根据
1、报文类型
2、报文参数1
3、报文参数2 做不同处理。用那两个参数实现多帧数据。处理完该报文之后还要回发“应答”报文,否则另一端会一直发。
我一般都是直接用winapi socket做的,控件不会用。
不知对楼主有没有帮助,惭愧说一声,我还不知道NAT是什么东西