我也问个,关于WINSOCK TCP多连接的问题

mdejtod 2009-10-26 06:00:27
RT。。。
1.在服务器端,使用网络消息通知模式处理的情况下(wsaasyncselect),
每连接一个客户端,就会生成一个新的 socket来跟客户端进行通讯。。。
而原来创建的socket 则可以继续监听客户端来的连接,
问题来了,在多个客户端连接的情况下,是不是每有一个客户端连接,都得定义一个对应的socket来与客户端进行通讯?
那几千上万个客户端连接时,怎么搞?
2.TCP连接的情况下进行nat穿透的问题(通过客户端的socket进行端口重用的方式实现,setsock()函数重定位端口和地址)。
如果两个客户端的NAT网络类型达不到要求(具体的忘了)时,是不是就不能实现P2P的功能?
...全文
380 29 打赏 收藏 转发到动态 举报
写回复
用AI写文章
29 条回复
切换为时间正序
请发表友善的回复…
发表回复
浮云V流水 2009-11-30
  • 打赏
  • 举报
回复
好贴,能否把你完成的程序DEMO贴出来,学习下。
yinrn815 2009-10-27
  • 打赏
  • 举报
回复
你的应用是什么样的?如果是长连接(接收客服端的连接后,就一直处于连接状态),那很好处理,原来创建的监听套接字让它一直处于监听状态,建一个套接字管理的类,维护管理客服连接的套接字对象,对每一个套接字注册读写、关闭、出错事件,对事件消息写对应的方法处理,也可采用线程方式实现。
如果是短连接(接收客服连接,读取客服发来的数据,然后发送返回数据包,关闭客服端连接),上万的客服连接,建议监听的套接字让他一直处于监听,与客服端通讯(接收,发送数据)建议采用线程池处理,祝你好运!!
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
顶起来,有没有高人搞过TCP穿透?
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
多连接问题已经解决,现在是关于客户端与客户端连接的问题了
在客户端创建 socket 时加了这句,使地址端口重用
var Flag : boolean;
addr : tsockaddrIn;
Flag := true;
setsockopt(FSock,SOL_SOCKET,SO_REUSEADDR,@Flag,sizeof(Boolean));
//并且返回成功
但是我在重新在绑定 Fsock的端口时,返回错误
如:获取到对方的地址后,将自己作为服务器端,重新绑定端口,并开启监听,等待对方连接
addr.sin_family := PF_INET;
addr.sin_port := htons(5236);
addr.sin_addr.s_addr := INADDR_ANY;
bing(FSock,addr,sizeof(addr)); //返回错误
不知道哪位有没有处理过这种情况?
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
看来是得为双方都开一个socket监听一个端口,不过我觉得,两者连接成功的可能性不大,明天试下,谢谢!
XD王 2009-10-27
  • 打赏
  • 举报
回复

procedure WndProc(var AMsg: TMessage);
var
Error: word;
begin
with AMsg do
case Msg of
WM_ASYNCSELECT: // 自定义消息头
begin
Error:= WSAGetSelectError(LParam);
case WSAGetSelectEvent(LParam) of
FD_READ : TCPServerData(WParam); // WParam 为 对应的 Socket
FD_ACCEPT: OpenConnection(WParam, Error);
FD_CLOSE : CloseConnection(WParam, Error);
end;
end;
else
Result:= DefWindowProc(FHandle, Msg, WParam, LParam);
end;
end;

每个客户端进来的消息中,都包含了他的socket,服务器只需要针对它做应答就可以了
haitao 2009-10-27
  • 打赏
  • 举报
回复
tcp下,一旦A要连B,B就是服务端了,B必须有侦听某个端口(pb),A才能作为一个客户端来连接,连接成功,A会得到一个动态的本地端口pa,实现:ip1:pa==>ip2:pb
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
顶。。。起来
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
谢谢各位,现在可以了,服务器端是要为第个连接的客户端都准备一个新的 socket ,在服务器端用一个结构数组保存了所有客户端的信息,包括连接后所用的 socket,在服务器端的消息事件处理中
WSAGetSelectEvent(msg.wparam);就可以知道当前会话的是哪一个客户端...
多连接的问题解决了
不过还有一个问题,就是关于 通过setsockopt()这个函数,在客户端改变连接的IP和端口号,具体不知道怎么用
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 sz_haitao 的回复:]
S在p端口侦听,A以ip1、p1端口连上来,B以ip2、p2端口连上来
A得到S告知的B的ip2,可以利用,但是p2是无法使用的,因为p2是B作为客户端的端口,并不是B在p2也侦听了
这与udp是不一样的
tcp要求:B必须在一个特定的端口pb侦听,然后告知S,A才能连ip2的pb端口
[/Quote]
不太明白,你的意思是,如果两个客户端要连接,那两端都必须重新建过一个 socket 然后绑定一个新的端口来监听吗?
gwhdaxia 2009-10-27
  • 打赏
  • 举报
回复
前几天看了下这些模型,但是理解不深,这里讨论一下最好
gwhdaxia 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 sz_haitao 的回复:]
你的AcceptSock是什么?全局的?怎么都是使用它?
哪个socket,应该是SOCKET sock = (SOCKET) wParam;

好像这则说的不错:
http://blog.chinaunix.net/u3/103892/showart_2050171.html
[/Quote]

我觉得问题应该就是在AcceptSock这里
c58342418 2009-10-27
  • 打赏
  • 举报
回复
好帖,顶起来,关注中 ~~~~
haitao 2009-10-27
  • 打赏
  • 举报
回复
S在p端口侦听,A以ip1、p1端口连上来,B以ip2、p2端口连上来
A得到S告知的B的ip2,可以利用,但是p2是无法使用的,因为p2是B作为客户端的端口,并不是B在p2也侦听了
这与udp是不一样的
tcp要求:B必须在一个特定的端口pb侦听,然后告知S,A才能连ip2的pb端口
XD王 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 22 楼 mdejtod 的回复:]
......
然后在客户端上用原来连接到 S端的socket 进行监听,并连接。。。
可结果总是不成功!!!!
[/Quote]
先不管这样的方式对不对,就监听来说,只需要原来的端口号就可以了,而不是socket,所以会不成功。
作为客户端,它原先connect服务器,其本地端口是系统分配的,必须先提取这个参数。

以上是我的一些看法,不对之处还请指正。
sanguomi 2009-10-27
  • 打赏
  • 举报
回复
TCP是有连接数限制的
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
to: XD19861130
我的想法是这样的,只不过不太明白何谓一个主连接,一个协助连接
目前程序的结构就是这样:服务器端(S)建立一个 Socket 用来监听客户端来的连接
每个客户端连接后,就记录客户端的信息,包括IP,端口,对应的通信socket 等等
现在A,B都连接到了S端,那就S端就有三个socket,包括原先的监听socket,分别与客户端A,B连接后的 socketA,socketB ,我现在的做法就是,服务器端收到A要连接B的请求后,从S端返回B的IP和PORT给A,同时,给B发送A的IP和PORT信息。
然后在客户端上用原来连接到 S端的socket 进行监听,并连接。。。
可结果总是不成功!!!!
mdejtod 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 yinrn815 的回复:]
你的应用是什么样的?如果是长连接(接收客服端的连接后,就一直处于连接状态),那很好处理,原来创建的监听套接字让它一直处于监听状态,建一个套接字管理的类,维护管理客服连接的套接字对象,对每一个套接字注册读写、关闭、出错事件,对事件消息写对应的方法处理,也可采用线程方式实现。
如果是短连接(接收客服连接,读取客服发来的数据,然后发送返回数据包,关闭客服端连接),上万的客服连接,建议监听的套接字让他一直处于监听,与客服端通讯(接收,发送数据)建议采用线程池处理,祝你好运!!
[/Quote]
是长连接,主要是想写成像UDP一样的点对点的传输,至于服务器端与客户端的通信倒不是很重要,目前就是
网络消息的方式管理服务器端与客户端的连接
XD王 2009-10-27
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 mdejtod 的回复:]
多连接问题已经解决,现在是关于客户端与客户端连接的问题了
在客户端创建 socket 时加了这句,使地址端口重用
var Flag : boolean;
    addr : tsockaddrIn;
  Flag := true;
  setsockopt(FSock,SOL_SOCKET,SO_REUSEADDR,@Flag,sizeof(Boolean));
  //并且返回成功
但是我在重新在绑定 Fsock的端口时,返回错误
如:获取到对方的地址后,将自己作为服务器端,重新绑定端口,并开启监听,等待对方连接
  addr.sin_family := PF_INET;
  addr.sin_port := htons(5236);
  addr.sin_addr.s_addr := INADDR_ANY;
  bing(FSock,addr,sizeof(addr)); //返回错误
不知道哪位有没有处理过这种情况?
[/Quote]
不知道LZ重新绑定的是哪个端口,好像客户端只需要绑定一次就可以了。
服务器一般单独监听一个辅助打洞的端口 P,假如客户端A去请求打洞去连接B,则通过SERVER的端口P向B传输经过A转换后的公网IP地址和端口等信息, B收到后首先连接server端口P,随便发点消息后马上断开。这样做的目的是让S能知道B经过NAT-B转换后的公网IP和端口号。
  B尝试与A的公网IP地址和端口进行connect,根据不同的路由器会有不同的结果,有些路由器在这个操作就能建立连接,大多数路由器对于不请自到的SYN请求包直接丢弃而导致connect失败,但A端的路由器会纪录此次连接的源地址和端口号,为接下来真正的连接做好了准备,这就是所谓的打洞,即B向A打了一个洞,下次A就能直接连接到B刚才使用的端口号了。
客户端B打洞的同时在相同的端口上启动侦听。B在一切准备就绪以后通过与S的【主连接】回复消息“我已经准备好”,S在收到以后将B经过NAT-B转换后的公网IP和端口号告诉给A。
A收到S回复的B的公网IP和端口号等信息以后,开始连接到B公网IP和端口号,由于B曾经尝试连接过A的公网IP地址和端口,NAT-A纪录了此次连接的信息,所以当A主动连接B时,NAT-B会认为是合法的SYN数据,并允许通过,从而直接的TCP连接建立起来了。

以上是网络上说的一种方法,确实可行,LZ可以参考下

mdejtod 2009-10-26
  • 打赏
  • 举报
回复
是全局的 AcceptSock 是 Server 端建立一个新的 socket 来对此连接做服务,而原先的 socket 则再回到监听等待的状态
加载更多回复(9)

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧