コード例 #1
0
        //粘包处理
        public static bool StickyDeal(SocketAsyncEventArgs e)
        {
            AsyncUserToken token = (AsyncUserToken)e.UserToken;

            //复制数据
            //e.Buffer中的数据要等到下一次调用异步接收时才会自动清除
            //所以一次异步接收后,只用复制一次数据就行,这里要想办法规避掉第二次复制
            if (!token.isCopy)
            {
                byte[] data = new byte[e.BytesTransferred];
                Array.Copy(e.Buffer, e.Offset, data, 0, e.BytesTransferred);
                Console.WriteLine("data的大小 : " + data.Count());
                //将数据放入receiveBuffer
                //receiveBuffer是list<byte>类型的
                lock (token.receiveBuffer)
                {
                    token.receiveBuffer.AddRange(data);
                }
                token.isCopy = true;
            }

            //粘包处理

            //接收到的数据长度还不足以分析包的类型和长度,跳出,让程序继续接收          TODO  break->return?
            if (token.receiveBuffer.Count < 8)
            {
                return(false);
            }
            //如果packageLen长度为0,就得到包长
            else if (token.packageLen == 0)
            {
                //得到包的类型
                byte[] typeByte = token.receiveBuffer.GetRange(0, 4).ToArray();
                token.packageType = BitConverter.ToInt32(typeByte, 0);
                //得到包的长度
                byte[] lenBytes = token.receiveBuffer.GetRange(4, 8).ToArray();
                token.packageLen = BitConverter.ToInt32(lenBytes, 0);
            }
            //接收到的数据长度不够,跳出,让程序继续接收     TODO    先分析包的类型再决定如何做?
            if (token.receiveBuffer.Count() < token.packageLen)
            {
                return(false);
            }
            //接收到的数据包最少有一个完整的数据,可以交给下面的函数处理
            else
            {
                return(true);
            }
        }
コード例 #2
0
ファイル: MClient.cs プロジェクト: gitwei2017/MIMSC
        //异步接收操作完成时调用此方法
        //如果远程主机关闭了连接,那么就关闭套接字
        //接收到了数据,将数据返回给客户端
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            AsyncUserToken token = (AsyncUserToken)e.UserToken;

            try
            {
                //检查这个远程主机是否关闭连接

                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    //使用MessageDeal类处理数据
                    //TODO  在有大量数据包发送过来时,因为忙着处理数据库,所以有数据没有接收到
                    //这里当数据大于8且不知道长度时,说明还有数据可以分析,那么就继续分析
                    //如果剩下的包足够长,那么数据就会被处理,不够长,那么下一次剩余数据到达,必然会调用一次这个函数,也能处理
                    do
                    {
                        MessageDeal.ReceiveDeal(e);
                    }while (token.receiveBuffer.Count > 8 && token.packageLen == 0);

                    //Thread thread = new Thread(()=>MessageDeal.ReceiveDeal(e));
                    //thread.Start();

                    //这里每一次接收到数据后,就会调用发送函数的回调函数
                    //那么后面服务端自己主动发送的时候,就需要自己主动调用了
                    if (token.sendPacketNum.Count() > 0)
                    {
                        //调用发送函数的回调函数
                        ProcessSend(sendSAEA);
                    }

                    //接收完继续接收
                    Console.WriteLine("开始异步接收");
                    token.isCopy = false;
                    bool willRaiseEvent = token.Socket.ReceiveAsync(e);
                    if (!willRaiseEvent)
                    {
                        ProcessReceive(e);
                    }
                }
                else
                {
                    CloseClientSocket();
                }
            }
            catch (Exception xe)
            {
                Console.WriteLine(xe.Message + "\r\n" + xe.StackTrace);
            }
        }
コード例 #3
0
        //异步接收操作完成时调用此方法
        //如果远程主机关闭了连接,那么就关闭套接字
        //接收到了数据,将数据返回给客户端
        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            AsyncUserToken token = (AsyncUserToken)e.UserToken;

            try
            {
                //检查这个远程主机是否关闭连接

                if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
                {
                    //增加服务器接收到的总字数
                    Interlocked.Add(ref m_totalBytesRead, e.BytesTransferred);
                    LogStringBuild.AppendFormat("The server has read a total of {0} bytes\n", m_totalBytesRead);
                    LogString = LogStringBuild.ToString();

                    //处理数据
                    MessageDeal.ReceiveDeal(e);

                    if (token.sendPacketNum.Count() > 0)
                    {
                        //调用发送函数的回调函数
                        ProcessSend(m_sendSaeaDic[token.Socket.RemoteEndPoint.ToString()]);
                    }

                    //将数据返回给客户端
                    //e.SetBuffer(e.Offset, e.BytesTransferred);
                    //这里是从读取到发送
                    Console.WriteLine("开始异步接收");
                    bool willRaiseEvent = token.Socket.ReceiveAsync(e);
                    if (!willRaiseEvent)
                    {
                        ProcessReceive(e);
                    }
                }
                else
                {
                    CloseClientSocket(e);
                }
            }
            catch (Exception xe)
            {
                Console.WriteLine(xe.Message + "\r\n" + xe.StackTrace);
            }
        }
コード例 #4
0
ファイル: MClient.cs プロジェクト: gitwei2017/MIMSC
        //用来打包要发送的数据的函数,只需要传入数据类型,保存数据的字符串和发送数据所用的SAEA就行
        public void SendMessage(int packageType, String str, SocketAsyncEventArgs e)
        {
            AsyncUserToken token = (AsyncUserToken)e.UserToken;
            //这里是要获得字节数而不是元素数
            int packageLen = System.Text.Encoding.Default.GetByteCount(str) + 8;

            Console.WriteLine("包的大小为" + packageLen);
            byte[] bType = System.BitConverter.GetBytes(packageType);
            byte[] bLen  = System.BitConverter.GetBytes(packageLen);
            //将数据放入发送buffer
            token.sendBuffer.AddRange(bType);
            token.sendBuffer.AddRange(bLen);
            token.sendBuffer.AddRange(System.Text.Encoding.Default.GetBytes(str));
            //接下来可以调用发送函数的回调函数了
            //下一次要发送多少数据
            token.sendPacketNum.Add(packageLen);
            Console.WriteLine("数据装载完毕");
            ProcessSend(sendSAEA);
        }
コード例 #5
0
        public static void UserInfoDeal(SocketAsyncEventArgs e)
        {
            MClient        mClient = MClient.CreateInstance();
            AsyncUserToken token   = (AsyncUserToken)e.UserToken;
            //得到一个完整的包的数据,放入新list,第二个参数是数据长度,所以要减去8
            List <byte> onePackage = token.receiveBuffer.GetRange(8, token.packageLen - 8);

            //将复制出来的数据从receiveBuffer旧list中删除
            token.receiveBuffer.RemoveRange(0, token.packageLen);
            Console.WriteLine("清除receiveBuffer中的数据 , token.packageLen = " + token.packageLen);
            //list要先转换成数组,再转换成字符串
            String jsonStr = Encoding.Default.GetString(onePackage.ToArray());
            //得到用户名和密码
            JObject obj = JObject.Parse(jsonStr);

            //如果传回来的用户信息是正确的
            if (obj["isOk"].ToString().Equals("True"))
            {
                Console.WriteLine("保存自己的信息");
                //先初始化数据库的静态变量(这里是用id合成数据库名)
                SqliteConnect.SqliteInit(obj["id"].ToString());
                //然后创建好友表和信息表(如果有,不会重复创建)
                SqliteConnect.CreateTable();
                //保存自己的最新信息到数据库
                SqliteConnect.SaveUserInfo(obj["id"].ToString(), obj["UserName"].ToString(), obj["RealName"].ToString(), obj["Sex"].ToString(),
                                           obj["BirthDay"].ToString(), obj["Address"].ToString(), obj["Email"].ToString(), obj["PhoneNumber"].ToString(),
                                           obj["Remark"].ToString());

                //主窗口隐藏
                Application.Current.Dispatcher.Invoke(new Action(() => { Application.Current.MainWindow.Hide(); }));
                //打开好友界面
                Application.Current.Dispatcher.Invoke(new Action(() => {
                    FriendListWindow friedListWindow = new FriendListWindow();
                    friedListWindow.Show();
                }));
            }
            else
            {
                MessageBox.Show("用户信息返回失败");
            }
        }
コード例 #6
0
ファイル: MClient.cs プロジェクト: gitwei2017/MIMSC
        //异步发送操作完成时调用此方法
        //该方法在套接字上发出另一个接收以读取任何其他接收  ??
        //从客户端发送的数据
        //
        //<param name = "e"></param>
        private void ProcessSend(SocketAsyncEventArgs e)
        {
            //服务端的sendSAEA的Iocomplete没有绑定完成事件,所以服务端SendAsync后不会重复调用ProcessSend
            //而客户端的绑定了,如果不加下面的跳出函数,会一直循环。
            //两种方法也说不上谁好,所以客户端先采用与服务端不同的方式,也许后面可以用于发送很大的数据
            if (((AsyncUserToken)e.UserToken).sendBuffer.Count == 0)
            {
                return;
            }

            Console.WriteLine(e.SocketError);

            if (e.SocketError == SocketError.Success)
            {
                //用来将sendSAEA.UserToken中已经准备好的数据发送出去
                AsyncUserToken token = (AsyncUserToken)e.UserToken;
                byte[]         data;
                int            count = token.sendBuffer.Count;

                //TODO 不能就这么莽撞地取出和发送所有数据,或许应该添加一个int类型的list,将下一次发送多少数据存入里面

                //从sendBuffer中取出数据
                data = token.sendBuffer.ToArray();
                token.sendBuffer.Clear();

                e.SetBuffer(data, 0, data.Length);

                Console.WriteLine("开始异步发送 datasize:" + data.Count() + "data:" + System.Text.Encoding.UTF8.GetString(data));
                bool willRaiseEvent = token.Socket.SendAsync(e);
                if (!willRaiseEvent)
                {
                    Console.WriteLine("调用了这个吗?");
                    ProcessSend(e);
                }
                Console.WriteLine("异步发送完毕");
            }
            else
            {
                CloseClientSocket();
            }
        }
コード例 #7
0
        public static void FriendInfoDeal(SocketAsyncEventArgs e)
        {
            MClient        mClient = MClient.CreateInstance();
            AsyncUserToken token   = (AsyncUserToken)e.UserToken;
            //得到一个完整的包的数据,放入新list,第二个参数是数据长度,所以要减去8
            List <byte> onePackage = token.receiveBuffer.GetRange(8, token.packageLen - 8);

            //将复制出来的数据从receiveBuffer旧list中删除
            token.receiveBuffer.RemoveRange(0, token.packageLen);
            //list要先转换成数组,再转换成字符串
            String jsonStr = Encoding.Default.GetString(onePackage.ToArray());
            //得到用户名和密码
            JArray jArray = JArray.Parse(jsonStr);


            if (jArray[0]["isOk"].ToString().Equals("True"))
            {
                Console.WriteLine("保存好友信息");

                //保存还没有更新前的时间,如果时间比这个时间还晚,说明是已经被删除的好友
                String updatetime = DateTime.Now.ToString();

                foreach (var obj in jArray)
                {
                    SqliteConnect.SaveFriendInfo(obj["id"].ToString(), obj["Group"].ToString(), obj["UserName"].ToString(), obj["RealName"].ToString(), obj["Sex"].ToString(),
                                                 obj["BirthDay"].ToString(), obj["Address"].ToString(), obj["Email"].ToString(), obj["PhoneNumber"].ToString(),
                                                 obj["Remarks"].ToString());
                }

                //在保存完好友信息后,就要根据更新时间对数据库表中的数据进行排查,删除掉这一次还没有更新的数据
                SqliteConnect.DeleteFriendByTime(updatetime);
            }
            else
            {
                //如果不进行这个补充,那么在只有一个好友,且服务端已经删除这个好友的情况下,客户端本地的该好友不会被删除
                String updatetime = DateTime.Now.ToString();
                SqliteConnect.DeleteFriendByTime(updatetime);
            }
        }
コード例 #8
0
ファイル: MClient.cs プロジェクト: gitwei2017/MIMSC
        //创建一个未初始化的服务器实例
        //开始监听
        //先调用Init方法,然后调用Start方法
        //
        //<param name = "numConnections">同时处理的最大连接数</param>
        //<param name = "receiveBufferSize">用于每个套接字操作的缓存区大小</param>
        private MClient(String ip, String port)
        {
            //初始化ip和port
            this.ip   = ip;
            this.port = port;
            //实列化两个SAEA,分别用于接收和发送
            this.readSAEA = new SocketAsyncEventArgs();
            this.sendSAEA = new SocketAsyncEventArgs();

            //TODO 分配缓存区


            //绑定完成事件
            this.readSAEA.Completed += new EventHandler <SocketAsyncEventArgs>(IO_Completed);
            this.sendSAEA.Completed += new EventHandler <SocketAsyncEventArgs>(IO_Completed);
            //分配信息保存空间
            AsyncUserToken userToken = new AsyncUserToken();

            this.readSAEA.UserToken = userToken;
            this.sendSAEA.UserToken = userToken;

            Console.WriteLine("MClient构造函数执行完毕");
        }
コード例 #9
0
        //异步发送操作完成时调用此方法
        //该方法在套接字上发出另一个接收以读取任何其他接收  ??
        //从客户端发送的数据
        //
        //<param name = "e"></param>
        private void ProcessSend(SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                //完成了将数据返回给客户端
                AsyncUserToken token = (AsyncUserToken)e.UserToken;
                byte[]         data;
                int            count = token.sendBuffer.Count;

                //if ( count > 1024)
                //{
                //    data = token.sendBuffer.GetRange(0, 1024).ToArray();
                //    token.sendBuffer.RemoveRange(0, 1024);
                //}
                //else
                //{
                //    data = token.sendBuffer.GetRange(0, count).ToArray();
                //    token.sendBuffer.RemoveRange(0, count);
                //}

                data = token.sendBuffer.ToArray();
                token.sendBuffer.Clear();

                e.SetBuffer(data, 0, data.Length);

                Console.WriteLine("开始异步发送 datasize:" + data.Count() + "data:" + System.Text.Encoding.UTF8.GetString(data));
                bool willRaiseEvent = token.Socket.SendAsync(e);
                if (!willRaiseEvent)
                {
                    ProcessSend(e);
                }
            }
            else
            {
                CloseClientSocket(e);
            }
        }
コード例 #10
0
        public static void RegisMessDeal(SocketAsyncEventArgs e)
        {
            MClient        mClient = MClient.CreateInstance();
            AsyncUserToken token   = (AsyncUserToken)e.UserToken;
            //得到一个完整的包的数据,放入新list,第二个参数是数据长度,所以要减去8
            List <byte> onePackage = token.receiveBuffer.GetRange(8, token.packageLen - 8);

            //将复制出来的数据从receiveBuffer旧list中删除
            token.receiveBuffer.RemoveRange(0, token.packageLen);
            //list要先转换成数组,再转换成字符串
            String jsonStr = Encoding.Default.GetString(onePackage.ToArray());
            //得到用户名和密码
            JObject obj = JObject.Parse(jsonStr);

            if (obj["isRegist"].ToString().Equals("True"))
            {
                MessageBox.Show("注册成功");
                //关闭注册窗口
                MClientViewModel  mClientViewModel  = MClientViewModel.CreateInstance();
                RegisterViewModel registerViewModel = RegisterViewModel.CreateInstance();
                //重置输入框
                registerViewModel.Resset();
                //跨线程调用窗体组件的方法,使注册窗口关闭
                mClientViewModel.registerWindow.Dispatcher.Invoke(new Action(() => {
                    mClientViewModel.registerWindow.Close();
                }));
            }
            else
            {
                MessageBox.Show("注册失败");
                //清除掉密码
                RegisterViewModel registerViewModel = RegisterViewModel.CreateInstance();
                registerViewModel.PassWord  = "";
                registerViewModel.sPassWord = "";
            }
        }
コード例 #11
0
        //对完整的数据进行分类处理
        public static void ClassifyDeal(SocketAsyncEventArgs e)
        {
            AsyncUserToken token = (AsyncUserToken)e.UserToken;
            messageType    type  = (messageType)token.packageType;

            //根据数据类型处理数据
            switch (type)
            {
            case messageType.landMessage:
                Console.WriteLine("登陆返回信息处理");
                LandMessDeal(e);
                break;

            case messageType.registMessage:
                Console.WriteLine("注册返回信息处理");
                RegisMessDeal(e);
                break;

            case messageType.UserInfo:
                Console.WriteLine("返回的该用户信息处理");
                UserInfoDeal(e);
                break;

            case messageType.FriendInfo:
                Console.WriteLine("返回的好友信息处理");
                FriendInfoDeal(e);
                break;

            case messageType.UserMessage:
                Console.WriteLine("返回的用户消息处理");
                UserMessageDeal(e);
                break;

            case messageType.friendrequestMessage:
                Console.WriteLine("返回的用户请求处理");
                FriendRequestMessageDeal(e);
                break;

            case messageType.AddFriendRetMessage:
                Console.WriteLine("返回的模糊搜索到的用户信息处理");
                AddFriendRetMessage(e);
                break;

            case messageType.ChangeGroupMessage:
                Console.WriteLine("返回的模糊搜索到的用户信息处理");
                ChangeGroupMessage(e);
                break;

            case messageType.DeleteFriendMessage:
                Console.WriteLine("返回的删除好友信息处理");
                DeleteFriendMessage(e);
                break;

            case messageType.FriendStatusMessage:
                Console.WriteLine("返回的好友状态信息处理");
                FriendStatusMessage(e);
                break;

            case messageType.ChangePassReturnMessage:
                Console.WriteLine("返回修改密码结果处理");
                ChangePassReturnMessage(e);
                break;

            default:
                //可能的处理
                break;
            }
            //将这两个标志归零
            token.packageLen  = 0;
            token.packageType = 0;
        }