吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 6321|回复: 7
收起左侧

[其他转载] QQ聊天程序的网络通信原理及编程(中)

[复制链接]
523740194 发表于 2011-6-8 17:42
本帖最后由 523740194 于 2011-6-8 17:43 编辑

QQ聊天程序的网络通信原理(4)发送登录的用户名和密码
客户端程序在服务端程序接受连接后会收到消息触发Connect事件,对客户端而言在Connect事件方法中发送登录用户名和密码是最佳时机,为了使接收数据的一方明白收到的数据代表什么含义,每条数据最前面有代表不同含义的数据含义标记字符串,每条数据后有相同的数据结束标记符,每条数据中各子数据间有子数据分割标记符。各数据含义标记字符串如下:
Public Const '表示本数据中包含在线好友的IP地址和ID
Public Const Login = "User Login" '表示本数据中包含登录用户的用户ID和密码
Public Const NotUser = "IsNot User"  '本数据含义为“不是合法用户”
Public Const  IsUser = "ThisIsUser"  '本数据含义为“是合法用户”
为了识别数据含义方便,含义标记字符串长度一致,我这里采用的长度为10。
Public Const HeadLength = 10
关于分割标记符和结束标记符,我采用数值1和2转字符的方法,因为它们转成的字符不是普通字符,不会和传送的数据如用户ID、密码、IP地址等字符串数据混淆。
具体发送数据通过SendData方法进行,发送登录用户名和密码的语句如下,数据的格式为:数据含义标记字符串+用户名+分割标记符+密码+结束标记符。
Private Sub WinsockClient_Connect()
WinsockClient.SendData Login & TextUsername.Text & Chr(1) & TextPassword.Text & Chr(2)
End Sub
(5)接收收据
当有数据到达时,程序会收到消息触发DataArrival事件,所以不论服务端还是客户端程序接收数据的工作在DataArrival事件方法中完成。具体接收数据使用GetData方法进行,为了防止客户端发送来的数据太多,服务端来不及处理,我定义了一个字符串数组BufferRecv,该数组与WinsockServer控件数组对应,WinsockServer(Index) 控件收到的数据添加在BufferRecv(Index)中,然后通过结束标记符在BufferRecv(Index)中取出一条条数据进行分析。如果是客户登录,则获取用户名和密码,然后通过自定义函数Lookfor在数据库中验证。如果验证为合法用户,则发送“是合法用户”数据标记,然后将用户ID和用户机器的IP等信息置于一个在线用户信息的结构数组中备用。然后通过自定义函数GetFriend在数据库中获取该用户的所有好友ID及好友人数,并根据在线用户信息数组逐一判断各个好友是否在线,如果在线,则将在线好友的ID及IP地址发送给刚登录的客户,同时也将刚登录客户的ID及IP地址发送给在线好友,以便他们相互之间能够通信。如果验证为非法用户,则发送“不是合法用户”数据标记,并将与该客户通信用的Winsock控件卸载。
Private Sub WinsockServer_DataArrival(Index As Integer, ByVal bytesTotal As Long)
Dim tmpstr As String
Dim EndFlagLoc As Integer ‘结束标记所处位置变量
If Index = 0 Then Exit Sub
WinsockServer(Index).GetData tmpstr, , bytesTotal ‘接收收据存入tmpstr中
BufferRecv(Index) = BufferRecv(Index) & tmpstr ‘将收到的数据添加在BufferRecv(Index)中
EndFlagLoc = InStr(BufferRecv(Index), Chr(2)) ‘在BufferRecv(Index)中寻找第一个结束标记符的位置
While EndFlagLoc > 0
    ‘在BufferRecv(Index)中取第一个结束标记符左边的数据,即第一条数据。
strMsg = Left$(BufferRecv(Index), EndFlagLoc - 1)
‘获取本条数据前面的数据含义标记字符串以分析本条数据的含义。
    Select Case Left$(strMsg, HeadLength)  
        Case Login ‘如果是登录数据
            Dim tmpPassWord As String
            Dim tmpUserID As String
            ‘通过Mid方法取得数据含义标记字符串之后分割标记符之前的数据,即登录用户名。
            tmpUserID = Mid(strMsg, HeadLength + 1, InStr(strMsg, Chr(1)) - 1 - HeadLength)
             ‘通过Mid方法取得分割标记符之后的数据,即登录密码。
            tmpPassWord = Mid(strMsg, InStr(strMsg, Chr(1)) + 1)
‘通过自定义函数Lookfor在数据库中查询该用户名密码是否存在,如存在则发送含义为“是合法用户”的数据,Lookfor函数的具体实现见源程序。
            If Lookfor(tmpUserID, tmpPassWord) Then
                WinsockServer(Index).SendData IsUser & Chr(2)
                DoEvents
‘将客户端的IP地址和用户ID等信息置于一个有关在线用户信息的结构数组中备用,并设置登录标志变量bLogined为True。
                OnlineUserInfo(Index).IPAddr = WinsockServer(Index).RemoteHostIP
                OnlineUserInfo(Index).UserID = tmpUserID
                  OnlineUserInfo(Index).bLogined = True
                Dim AllFriendID As String
                Dim FriendID As String
                Dim FriendCount As Integer
                Dim ToldFriendCount As Integer
‘然后通过自定义函数GetFriend在数据库中获取该用户的所有好友的ID及好友人数,分别放在参数AllFriendID和FriendCount中。
                If GetFriend(tmpUserID, AllFriendID, FriendCount) Then
‘然后根据在线用户信息数组用InStr函数逐一判断在线用户是否是该用户的好友。
                    For i = 1 To MaxOnlineUser
                        If OnlineUserInfo(i).bLogined Then
                            If InStr(AllFriendID, OnlineUserInfo(i).UserID) > 0 Then
‘如果是,则将在线好友的ID及IP地址发送给刚登录的客户。发送数据的格式为:数据含义标记字符串+IP地址+分割标记符+用户ID+结束标记符。
                                If WinsockServer(Index).State = sckConnected Then
                                    WinsockServer(Index).SendData OnlineFriendIPID & OnlineUserInfo(i).IPAddr & Chr(1) & OnlineUserInfo(i).UserID & Chr(2)
                                    DoEvents
                                End If
‘同时也将刚登录客户的ID及IP地址发送给在线好友,以便他们相互之间能够通信。
                                If WinsockServer(i).State = sckConnected Then
                                    WinsockServer(i).SendData OnlineFriendIPID & OnlineUserInfo(Index).IPAddr & Chr(1) & OnlineUserInfo(Index).UserID & Chr(2)
                                    DoEvents
                                End If
                                ToldFriendCount = ToldFriendCount + 1
                            End If
                        End If
                        If ToldFriendCount = FriendCount Then Exit For
                    Next i
                End If
‘如果验证为非法用户,则发送含义为“不是合法用户”的数据标记,并将与该客户通信用的Winsock控件卸载。
            Else
                WinsockServer(Index).SendData NotUser & Chr(2)
                DoEvents
                OnlineUserInfo(Index).bUsed = False
                WinsockServer(Index).Close
                Unload WinsockServer(Index)
            End If
‘然后从BufferRecv(Index)中删除已分析的这条数据,继续分析下一条数据。
    BufferRecv(Index) = Mid(BufferRecv(Index), EndFlagLoc + 1)
    EndFlagLoc = InStr(BufferRecv(Index), Chr(2))
Wend
End Sub
(6)客户端接收数据
客户端程序在收到数据后,对每条数据进行分析。如果不是合法用户,则显示“你不是合法用户!”;如果是合法用户,则隐藏登录窗体,显示聊天窗体;如果是在线好友信息,则提取该在线好友的ID及IP地址,然后通过自定义过程AddConnectOnlineFriend将该在线好友信息保存,并与该在线好友建立连接。
Private Sub WinsockClient_DataArrival(ByVal bytesTotal As Long)
Dim tmpstr As String
Dim EndFlagLoc As Integer
WinsockClient.GetData tmpstr, , bytesTotal
BufferCmd = BufferCmd & tmpstr
EndFlagLoc = InStr(BufferCmd, Chr(2))
While EndFlagLoc > 0
    strMsg = Left$(BufferCmd, EndFlagLoc - 1)
    Select Case Left$(strMsg, HeadLength)
        Case NotUser
            MsgBox "你不是合法用户!"
        Case IsUser
            MyID = TextUsername.Text ‘将用户ID保存在MyID中以备后用
            loginfrm.Hide
            Form1.Show
         Case OnlineFriendIPID
            Dim UserIP As String
            Dim UserID As String
            UserIP = Mid(strMsg, HeadLength + 1, InStr(strMsg, Chr(1)) - 1 - HeadLength)
            UserID = Mid(strMsg, InStr(strMsg, Chr(1)) + 1)
            Form1.AddConnectOnlineFriend UserID, UserIP
    End Select
    DoEvents
    BufferCmd = Mid(BufferCmd, EndFlagLoc + 1)
    EndFlagLoc = InStr(BufferCmd, Chr(2))
Wend
End Sub
自定义过程AddConnectOnlineFriend定义在聊天窗体中,首先将服务端发来的在线好友的IP地址和ID等保存在一个有关在线好友信息的结构型数组OnlineFriendInfo中,然后加载一个Winsock控件WinsockClientClient(i),用于给在线好友发送聊天信息,加载后同样要设置协议、远程IP地址、远程端口,然后以客户端方式请求与该好友连接。
Public Sub AddConnectOnlineFriend(UserID As String, UserIP As String)
    For i = 1 To MaxOnlineFriend
        If Not OnlineFriendInfo(i).bUsed Then
            OnlineFriendInfo(i).bUsed = True
            OnlineFriendInfo(i).IPAddr = UserIP
            OnlineFriendInfo(i).UserID = UserID
            Load WinsockClientClient(i)
            WinsockClientClient(i).Protocol = sckTCPProtocol
            WinsockClientClient(i).RemotePort = 6000
            WinsockClientClient(i).RemoteHost = OnlineFriendInfo(i).IPAddr
            If WinsockClientClient(i).State = sckClosed Then WinsockClientClient(i).Connect
            Exit For
        End If
    Next i
End Sub
所以在客户端程序中为了以服务端方式接受在线好友的连接,在聊天窗体加载时,要设置WinsockClientServer(0)这个Winsock控件,以便监听在线好友的连接。
Private Sub Form_Load()
WinsockClientServer(0).Protocol = sckTCPProtocol
WinsockClientServer(0).LocalPort = 6000
WinsockClientServer(0).Listen   '开始监听
End Sub
及编程(中)



希望大家能够支持

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

梦里何曾花落 发表于 2013-2-12 13:37
啊,这个有点复杂,呵呵,暂时没那水平看不懂,收藏了,谢谢
bjbcqy 发表于 2013-2-6 10:29
kirito 发表于 2013-2-6 08:58
l小白 发表于 2012-12-15 11:08
不懂。。但支持
zz12 发表于 2012-7-5 01:22
虽然不懂,但还是先收藏着
蓝冰8023 发表于 2011-12-8 09:30
学习中,支持楼主……
未登陆 发表于 2013-8-27 18:57
目前看不动这么高深的代码啊
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-16 08:37

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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