码迷,mamicode.com
首页 > 微信 > 详细

微信平台的模拟实现(2)---客户端开发

时间:2016-04-23 16:48:20      阅读:378      评论:0      收藏:0      [点我收藏+]

标签:

上一篇我们简单的分析了微信平台的实现原理,由于博主的表达比较欠缺,说的比较简单,可能看得不是很明白,不过随着一步步进行或者查看源码,大家就会清楚的明白了。

 

好了,不废话,这一篇我们先来实现客户端。

客户端的灵魂是基于socket实现即时通讯,消息的收发都要通过它。

为了看起累直观明了,我们为这个客户端包装一下,也就是加个界面,让它看起来更像一个客户端。

本文用的是wpf来做的界面,当然也可以以用winform窗体,看个人了。

本客户端主要有以下几个界面:

文件结构如下:

技术分享

1.登录/注册页面,为了简单,点击登陆就获取对应的账号密码登录,点击注册用的也是同样的输入框。

技术分享

2.登陆后的界面,底部有三个导航按钮,默认显示的是会话历史记录页面

技术分享

3.联系人页面

技术分享

4.“发现”页面,用于搜索公众号或者用户的界面

技术分享

 

下面主要来看一下客户端核心代码

 

技术分享
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows;

namespace wechat
{
    class Client
    {
        private static Interface_client client;
        private static int port = 8885;
        private static string serverIP = "127.0.0.1";
        private static Socket clientSocket;
        private static byte[] recResult = new byte[1024];
        private static Thread mainthread,recivethread;
        private static bool connected = false;


        public Client(int port, string serverIP, Interface_client client)
        {
            Client.port = port;
            Client.serverIP = serverIP;
            Client.client = client;
        }

        public Client( Interface_client client)
        {
            Client.client = client;
        }

        public void Start()
        {
            mainthread = new Thread(start);
            mainthread.IsBackground = true;
            mainthread.Start();
        }

        public void Stop()
        {
            mainthread.Abort();
        }

        public void Send(string content)
        {
            try { clientSocket.Send(Encoding.UTF8.GetBytes(content)); }
            catch { }
        }

        private void start()
        {
            
            //GetIPAndPort();
            IPAddress ip = IPAddress.Parse(serverIP);
            clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ////是客户端,同时也是服务器
            //clientSocket.Bind(new IPEndPoint(ip, port));
            //clientSocket.Listen(20);

            ConnectToServer(ip,client);
        }
        /*
         * 
         * 从输入获取ip和端口号
         * */
        private static void GetIPAndPort()
        {
            Console.WriteLine("enter the IPAddress ,default is :{0}", serverIP);
            GetAndCheckIpAddress();//判断输入的字符串是否为ip

            Console.WriteLine("enter the PORT ,default is :{0}", port);
            string tempPORT = Console.ReadLine();
            if (tempPORT.Length > 0)
                port = Convert.ToInt32(tempPORT);
        }
        //接入服务器
        private static void ConnectToServer(IPAddress ip, Interface_client client)
        {
            try
            {
                clientSocket.Connect(new IPEndPoint(ip, port));
                Console.WriteLine("connect to the server successful!");
                connected = true;
                clientSocket.Send(Encoding.UTF8.GetBytes("newconnection|"+Model.username));
                //开启消息和接收消息的线程
                //client.getMessage(clientSocket);
                recivethread = new Thread(RecMessage);
                recivethread.IsBackground = true;
                recivethread.Start(client);
            }
            catch (Exception e)
            {
                connected = false;
                MessageBox.Show("与连接失败......");
                Console.WriteLine(e.Message);
                //GetIPAndPort();
                Thread.Sleep(30000);
                MessageBox.Show("正在尝试重新连接......");
                ConnectToServer(ip,client);
            }
        }
        private static void SendMessage()
        {
            while (true)
                try { clientSocket.Send(Encoding.UTF8.GetBytes(Console.ReadLine())); }
                catch { }

        }

        private static void RecMessage(Object o)
        {
            Interface_client client = o as Interface_client;
            while (true)
            {
                try
                {
                    client.getMessage(clientSocket); 
                    //int recLength = clientSocket.Receive(recResult);
                    //getMessage(Encoding.UTF8.GetString(recResult, 0, recLength));
                    //Console.WriteLine("recive message from {0} : {1}",
                    //    clientSocket.RemoteEndPoint.ToString(),
                    //    Encoding.UTF8.GetString(recResult, 0, recLength));
                }
                catch (Exception e)
                {
                    connected = false;
                    //Console.WriteLine(e.Message);
                    MessageBox.Show("与服务器断开连接......");
                    //clientSocket.Shutdown(SocketShutdown.Both);
                    //clientSocket.Close();
                    Thread.Sleep(30000);
                    MessageBox.Show("正在尝试重新连接......");
                    //ConnectToServer(IPAddress.Parse(serverIP), client);
                    clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    while (!connected)
                    {
                        try
                        {
                            clientSocket.Connect(new IPEndPoint(IPAddress.Parse(serverIP), port));
                            Console.WriteLine("connect to the server successful!");
                            connected = true;
                            clientSocket.Send(Encoding.UTF8.GetBytes("newconnection|" + Model.username));
                            //开启消息和接收消息的线程
                            //client.getMessage(clientSocket);
                            recivethread = new Thread(RecMessage);
                            recivethread.IsBackground = true;
                            recivethread.Start(client);
                        }
                        catch (Exception e1)
                        {
                            MessageBox.Show("与连接失败......");
                            Console.WriteLine(e1.Message);
                            //GetIPAndPort();
                            Thread.Sleep(30000);
                            MessageBox.Show("正在尝试重新连接......");
                        
                        }
                    }
                    break;
                }
            }
        }

        private static void GetAndCheckIpAddress()
        {
            string tempIP = Console.ReadLine();
            if (tempIP.Length <= 0) return;
            if (IsIpAddress(tempIP))
            {
                serverIP = tempIP;
            }
            else
            {
                Console.WriteLine("the IP you‘ve enter is not right,please enter again ,default is :127.0.0.1");
                GetAndCheckIpAddress();
            }
        }
        private static bool IsIpAddress(string str)
        {
            string[] strings = str.Split(.);
            if (strings.Length != 4) return false;
            else
            {
                for (int i = 0; i < 4; i++)
                {
                    string tempstring = strings[i];
                    if (tempstring == "") return false;
                    int temp = Convert.ToInt32(tempstring);
                    if (temp >= 0 && temp <= 255) continue;
                    else return false;
                }
            }
            return true;
        }
    }

}
View Code

这个是socket客户端类Client,这个类开了一个专门接收消息的接口,实际用的时候要传入实现了 interface_client 接口的类的对象

使用接口是为了能够根据情况的不懂,对接收到的数据进行不同的解析方式,而且不会乱。

技术分享
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Windows;

namespace wechat
{
    class MyClient : Interface_client
    {
        public delegate void ReciveMessageHandle(string content);
        public static ReciveMessageHandle ReciveMessage;

        private static byte[] recResult = new byte[2048];
        string getdata;
        void Interface_client.getMessage(System.Net.Sockets.Socket clientSocket)
        {
            //while (true)
            //{
                try
                {
                    int recLength = clientSocket.Receive(recResult);
                    getdata = Encoding.UTF8.GetString(recResult, 0, recLength);
                    if (getdata.Length > 0)
                        ReciveMessage(getdata);
                        //MessageBox.Show(getdata);
                    //getMessage(Encoding.UTF8.GetString(recResult, 0, recLength));
                    //Console.WriteLine("recive message from {0} : {1}",
                    //    clientSocket.RemoteEndPoint.ToString(),
                    //    Encoding.UTF8.GetString(recResult, 0, recLength));
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();
                    //break;
                }
            //}
        }
    }
}
View Code

 

实现了interface_client 接口的类 MyClient ,实现了具体接收数据的方法,这里仅简单的接收字符串。

 

技术分享
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseSqlHelper;
using System.Data.SqlClient;
using System.Data;
using System.Xml;
using System.IO;

namespace wechat
{
    class DBTool
    {
        static SqlHelper helper = new SqlHelper(@"Data Source=MENG\SQLEXPRESS;Initial Catalog=wechat;Integrated Security=True");


        public static int register(string username,string pwd){
           try{ return helper.ExecuteNonQuery("insert into users(username,pwd,usertype) values (@username,@pwd,@usertype)",
                new SqlParameter("@username", username), new SqlParameter("@pwd", pwd), new SqlParameter("@usertype", "0"));
           }
            catch{return 0;}
        }


        public static int login(string username,string pwd){
           try{ return (int)helper.ExecuteScalar("select count(1) from users where username=@username and pwd = @pwd",
                new SqlParameter("@username", username), new SqlParameter("@pwd", pwd));
           }
            catch{return 0;}
        }


        public static DataTable search(string username, string findusername)
        {
            return helper.GetDataSet(@"select * ,type = case when usertype=‘0‘ then ‘普通用户‘ else ‘公众号‘ end 
                                    from users where username != @username and username like ‘%‘+@findusername+‘%‘", new SqlParameter("@username", username),
                                                                                                 new SqlParameter("@findusername", findusername)).Tables[0];
        }

        public static DataTable getuserinfo(string username,string viewusername)
        {
            return helper.GetDataSet(@"select * ,type = case when usertype=‘0‘ then ‘普通用户‘ else ‘公众号‘ end ,
                (select COUNT(1) from friend where username=@username and friendname=@viewusername) isfriend
                from users  where username =@viewusername", new SqlParameter("@username", username), new SqlParameter("@viewusername", viewusername)).Tables[0];
        }

        public static int addfriend(string username, string viewusername)
        {
            try
            {
                return helper.ExecuteNonQuery("insert into friend(username,friendname) values (@username,@viewusername)",
                    new SqlParameter("@username", username), new SqlParameter("@viewusername", viewusername));
            }
            catch { return 0; }
        }

        public static int delfriend(string username, string viewusername)
        {
            try
            {
                return helper.ExecuteNonQuery("delete from friend where username=@username and friendname=@viewusername",
                    new SqlParameter("@username", username), new SqlParameter("@viewusername", viewusername));
            }
            catch { return 0; }
        }

        public static DataTable getmyfriend(string username)
        {
            return helper.GetDataSet(@"select users.* ,[type] = case when users.usertype=‘0‘ then ‘普通用户‘ else ‘公众号‘ end 
                        from friend  left join users on users.username = friend.friendname where friend.username = @username ", 
                                    new SqlParameter("@username", username)).Tables[0];
        }

        public static int addhistdialog(string username, string viewusername)
        {
            try
            {
                return helper.ExecuteNonQuery(@"if exists (select * from histdialog where fromusername =@fromusername and tousername =@tousername)
                    return else insert into histdialog(fromusername,tousername) values (@fromusername,@tousername)",
                    new SqlParameter("@tousername", username), new SqlParameter("@fromusername", viewusername));
            }
            catch { return 0; }
        }

        public static DataTable gethistdialog(string username)
        {
            return helper.GetDataSet(@"
                    select users.* ,[type] = case when users.usertype=‘0‘ then ‘普通用户‘ else ‘公众号‘ end ,
                    (select count(1) from messages where messages.tousername=histdialog.tousername 
                    and  messages.fromusername=histdialog.fromusername and readstate=‘0‘ )unread
                    from histdialog 
                    left join users on users.username = histdialog.fromusername 
                    where histdialog.tousername = @username",
                                    new SqlParameter("@username", username)).Tables[0];
        }


        public static int getunreadcount(string username)
        {
            try
            {
                return (int)helper.ExecuteScalar("select count(1) from messages where tousername=@username and readstate=‘0‘",
                new SqlParameter("@username", username));
            }
            catch { return 0; }
        }

        public static int setreaded(string username,string fromusername)
        {
            try
            {
                return (int)helper.ExecuteScalar("update messages set readstate=‘1‘ where tousername=@username and fromusername=@fromusername",
                new SqlParameter("@username", username), new SqlParameter("@fromusername", fromusername));
            }
            catch { return 0; }
        }

        public static DataTable getmessageofdialog(string username,string fromusername)
        {
            return helper.GetDataSet(@"select * from messages where (tousername=@username and fromusername =@fromusername) or (fromusername=@username and tousername =@fromusername) order by id asc",
                new SqlParameter("@username", username), new SqlParameter("@fromusername", fromusername)).Tables[0];
        }


        public static Dictionary<string ,string> getxmlstring(string xmlcontent)
        {
            DataSet dsData = new DataSet();
            Dictionary<string, string> dictionary = new Dictionary<string, string>();
            dsData.ReadXml(new XmlTextReader(new StringReader(xmlcontent)));
            DataTable dt = dsData.Tables["HH"];


            foreach (DataRow dr in dt.Rows)
            {
                foreach (DataColumn dc in dr.Table.Columns)
                {
                    string n = dc.ColumnName;
                    string value = dr[n].ToString();
                    dictionary.Add(n, value);
                }
            }
            return dictionary;
        }

    }
}
View Code

DBTool类是对数据库数据操作的类(这里需要说明的是,在实际的这类客户端开发中,并不会直接的链接到数据库读写数据,

而是通过向服务器发送请求,服务器返回比如xml或者json之类的数据,客户端再解析,我猜也因该是这样的。这里为了偷懒,就除了通讯,其它的聊天记录,联系人等直接通过数据库获得)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace wechat
{
    class Model
    {
        public static string userid = "";
        public static string username = "";
        public static string viewusername = "0";
        public static string ontalkingusername = "";
        public static Client client;

        public static void SendMessage(string content)
        {
            client.Send(Model.username + "|" + Model.viewusername + "|" + content + "|" + DateTime.Now.ToString());
        }

    }
}

这个模型类是一个静态类,里边有一些静态属性,在这里用于保存一些数据用于传递数据,这个是本文所采用的解决方案,目前也不知道有什么好的办法在wpf里边传递数据,望知道的朋友不吝赐教。

 

if (DBTool.login(text_username.Text, text_pwd.Password) == 1)
            {
                //MessageBox.Show("登录成功!");
                Model.username = text_username.Text;
                new MainWindow().Show();
                this.Hide();
                Model.client = new Client(new MyClient());
                Model.client.Start();
            }

客户端在用户登录成功后才开始链接到我们开发的服务器(后面会讲到),只有连接上了服务器才能进行通讯。

注意:这里的client 用静态类里的client 来保存,是为了我们在其它地方发送消息时直接使用静态类里的client 发送消息即可。

 

前台界面用了较多的委托事件来触发消息的提示和某些ui的刷新,这个在这里也不是一言两语说得清楚,还不清楚委托的朋友可以先了解一下再看代码,这样有利于理解。

 

微信平台的模拟实现(2)---客户端开发

标签:

原文地址:http://www.cnblogs.com/mengtree/p/5424634.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!