研究QQ、Fetion、Msn的socket连接
LumaQQ 发送信息流程:
MessageManager.SendIM
PackageManager.Sendpacket: port = QQPort.Main.Name
ConnectionManager.EnsureConnection == 确认ConnectionPool 建立socket链接
ConnectionPool. Send = IConnection.Send()
TCPConnection.Send
SocketConnection.Send = socket.Send(sendBuf.ToByteArray(), 0, sendBuf.Length, SocketFlags.None);
发送后就没有下文了。
关闭发送:
ConnectionPool.Release(id)
SocketConnection.Close
当ConnectionPool.newTCPConnection的时候发生。
当QQPOrt.Create的时候发生。
当EnsureConnection的时候发生。
可以看见,发送信息后,socket被闲置了。 发送的端口是80. = LoginPort
小结发送:
本质上,发送信息等都是一种socket短链接。
客户端发送之后,如果不需要服务器ack,则断开链接(代码中并没有。)
基本上所有的发送package都需要服务器ack。 如果需要ack,则package发送之后,压入重发堆栈,直到超时、收到ack。
接收代码分析:
LoginManager.Logn()QQClient.LoginPort = QQGlobal.QQ_PORT_TCP; 实际上也是80端口。
然后也是来到了PackageManager.SendPackageAnyway.
QQClient.ConnectionManager.ConnectionPool.Send(port, packet, false);
看来是接收还是发送,就是一个标志位:
if (QQClient.ConnectionManager.EnsureConnection(port, true)) 表示接收 true = start 但是默认都是true
所以登录之后,当发送第一个package的时候,代码首先创建了SocketConnection. 这个时候就进入了等待状态。 Receive.
同时发送的时候仍然使用了这个socket。 即发送和接收都是一个socket。即使他之前在等待接收信息。
小结一下LumaQQ的工作流程:
登录的时候, packetmanager初始化trigger(packetincometrigger/resendtrigger/keepalivetrigger)
然后调用了 QQClient.PacketManager.SendPacketAnyway(outPacket, QQPort.Main.Name);
来到Packetmanager=> if (QQClient.ConnectionManager.EnsureConnection(port, true))
=> IConnection conn = QQPort.GetPort(portName).Create(QQClient, QQClient.LoginServerHost, QQClient.LoginPort, start);
来到OOPort.Create: policy = new ConnectionPolicy(client, Name, ProtocolFamily.Basic, ProtocolFamily.Basic);
而这个狗屁Policy.ID = QQPOrt.name
然而这个狗屁QQPort.Name实际上只有一个值是有意义的 = Main。真他妈的设计者脑子里面装的是什么狗屎垃圾。所以最终发现这个垃圾policy.id永远是一样的。 导致了ConnectionPool获取的Connection也一定是唯一一个。
这样就创建了一个等待接收的socket 。然后发送的时候是:
QQClient.ConnectionManager.ConnectionPool.Send(port, packet, false);
socket接收到信息后,放入queue(@Packetmanager), 同时在ThreadExcutor添加了一个trigger。(恶心的代码是在trigger使用标志位isrunning判断当前trigger是否正在运行。而这个trigger竟然是packetmanager的一个field。)
PacketIncomeTrigger被唤醒之后,调用了Call。
他就调用了Packetmanager.RemoveIncomingPacket / FirePacketArrivedEvent。
然后就调用了ProcessorRouter=>IPacketListener => BasicFamilyProcessor.PacketArrived =>
MessageManager.OnReceiveNormalIM => 调用了代理回调到了客户。
马勒戈壁的,突然发现一个狗屁Policy.ID去调用缓存了的connection. 真他妈的什么代码。简直就是浪费时间。
一句话小结,整个LumaQQ就是一堆垃圾,可以去烧了。没有任何步骤可言、没有任何架构思想;接收和发送使用相同的socket,而且没有去考虑是否断线了。之类的。做了个好像短链接的东西,实际上还是原来正在BeginReceive的connection。我 FUCK!
------------------------------------------------------------------
Fetion 估计也是类似的FUCKing 设计。因为参与设计的人就是那些。
一切从登录开始:Login=>
this.connection = new SipConnection();
LoginManager. GetSysConfig(user, connection);
SIPCSingInStep1 => connection.Connect(addrStrArr[0], addrStrArr[1]); =?>this.socket = TcpHelper.CreateSocket(ip, port);
string result = TcpHelper.SendAndReceive(connection.SipSocket, sendData);
SIPCSingInStep2 string result = TcpHelper.SendAndReceive(connection.SipSocket, sendData);
MyFetion.Initialize = this.connection.StartListen(this.user.Uri);+>this.ListenAsync(this.socket);+state.BeginReceive
基本上思路类似,开了socket之后等待,同时日后的发送仍然时候了这个socket。
------------------------------------------------------------------
最后是MSN。
messenger.Connect();
nsMessageProcessor.Connect(); (@SocketMessageProcessor)
socket = GetPreparedSocket(); =》socket).BeginConnect=》BeginDataReceive
NSMessageHandler=> MessageProcessor.SendMessage(new NSMessage("XFR", new string[] { "SB" }));
最后就是SocketMessageProcessor.SendSocketData()
结构比较流水,虽然臃肿,但是没有luma这么垃圾。
------------------------------------------------------------------
最后看看GTalk。看看牛人如何玩socket
XmppClientConnection xmppCon = new XmppClientConnection();
xmppCon.Open();
OpenSocket();
SocketConnect(base.Server, base.Port);
ClientSocket.Connect();
_socket.BeginConnect(endPoint, new AsyncCallback(EndConnect), null);
this.Receive();
我C!!!马勒戈壁的。看见没有!!GTALK的代码就是如此的简洁!这才是代码!这才是享受! 这才叫做开源!!!称得上开源的,拜托!请先像XMPP这样,简洁明了。并且没有错误。否则,不是开源,而是丢弃、放弃!
马勒戈壁的。。。看了一堆不爽的代码,到了gtalk才看到一点像样的东西。。。。