首页 > 代码库 > C#作业总结 (5)

C#作业总结 (5)

这一块总结程序的核心部分,局域网内的聊天,这部分我没有使用固定的服务器,而是通过UDP确定聊天的对象,然后双方通过TCP进行聊天,点对点式的聊天。

首先分析一段TCP的服务器和客户端的代码,基本这个代码看懂了就差不多

服务器部分

#region   通信协议说明  //  CONNECT|客户端名称          服务器接收  发送不同的客户端  初始化聊天室  //  LISTEN|聊天室其他用户名称    客户端接收  初始化聊天室  //  CHAT|客户名称|内容          服务器接收  发送消息  //  JOIN|客户端名称             客户端接收  增加显示聊天室新增人员  //  LEAVE|客户端名称            客户端接收  和上面相反  //  QUIT|                      客户端接收  服务器关闭  #endregion
 m_listener = new TcpListener(int.Parse(textBox2.Text));        //实例化监听对象            m_listener.Start();                                            //开启监听            while(true&&m_isStart)                                                   {                 Socket s = m_listener.AcceptSocket();                      //连接客户端                clientSocket=s;                                            //赋值                clientService = new Thread(new ThreadStart(ServiceClient));//开启客户端服务线程   每一个新的客户端都会分配一条新的线程                clientService.Start();                                     //开始服务            }
View Code
 Socket client=clientSocket;            bool isAlive = true;            while(isAlive&&m_isStart)            {                Byte[] buffer = new Byte[100000];                client.Receive(buffer);                                                          //服务器接收消息                string messageinfo = System.Text.Encoding.Default.GetString(buffer);             //默认编码                string[] tokens = messageinfo.Split(new char[] { | });                         //分割字符串                switch(tokens[0])                                                                //头部消息                {                       case "CONNECT":                                    for(int i=0;i<m_clients.Count;i++)                           //存在一个客户端连接  将新的客户的名称发送给其他客户                                    {                                        Client cl = (Client)m_clients[i];                                                      SendToClient(cl, "JOIN|" + tokens[1]);                   //发送加入消息                                    }                                    EndPoint ep = client.RemoteEndPoint;                         //获取该客户端的相关信息                                    Client c = new Client(tokens[1], ep, clientService, client); //实例化一个客户端                                    m_clients.Add(c);                                            //增加到客户端列表                                    string message="LISTEN|"+GetNameLists()+"\r\n";              //发送其他客户端的名称给新的客户  初始化客户列表                                    SendToClient(c, message);                                    //发送                                    break;                    case "CHAT":    for(int i=0;i<m_clients.Count;i++)                                                      {                                        Client cl = (Client)m_clients[i];                        //发送聊天消息                                        SendToClient(cl,messageinfo);                                    }                                    break;                    case "LEAVE":   int removeindex = 0;                                    bool found = false;                                                        for (int i = 0; i < m_clients.Count; i++)                                    {                                        Client cl = (Client)m_clients[i];                        //某个客户离开   匹配寻找并向其他客户端发送离开消息                                        SendToClient(cl, messageinfo);                                                                  if (cl.Name.CompareTo(tokens[1])==0)                                                                {                                            removeindex=i;                                            found = true;                                        }                                    }                                    if (found)                                        m_clients.RemoveAt(removeindex);                       //客户列表移除                                    client.Close();                                    isAlive = false;                                           //关闭连接  关闭这个客户的线程                                    break;                }            }
View Code
        #region 变量声明        private Thread client_thread;   //客户端服务线程        private EndPoint endpoint;      //客户端电脑相关信息        private string name;            //客户名称        private Socket sock;            //客户端Socket实例        #endregion        #region 构造函数        public Client(string _name, EndPoint _endpoint, Thread _thread, Socket _sock)        {            name = _name;            endpoint = _endpoint;            client_thread = _thread;            sock = _sock;        }        #endregion        #region  CLR属性         public Thread Client_Thread        {            get { return client_thread; }            set { client_thread = value; }        }        public EndPoint Host        {            get { return endpoint; }            set { endpoint = value; }        }        public string Name        {            get { return name; }            set { name = value; }        }        public Socket Sock        {            get { return sock; }            set { sock = value; }        }        #endregion 
View Code

客户端和上面差不多,基本都是分析协议头,然后执行相关的操作。

        private void ReceiveChat()        {            bool alive = true;            while (m_isConnected && alive)            {                Byte[] buffer = new Byte[100000];                                    //接收服务器消息                m_ns.Read(buffer, 0, buffer.Length);                                                 string time = System.DateTime.Now.ToLongTimeString();                //获取当前时间                    string chatter = System.Text.Encoding.Default.GetString(buffer);     //默认编码  主要是针对中文字符                string[] tokens = chatter.Split(new Char[] {|});                   //分离获取消息                switch (tokens[0])                                                   //头部消息                {                    case "CHAT":                        allmessage.AppendText(tokens[1].Trim());                     //增加客户名称和时间                        allmessage.AppendText("  " + time + " \r\n");                         allmessage.AppendText(tokens[2]);                            //增加消息内容                        break;                    case "JOIN":                        allmessage.AppendText(time + "  ");                                                  allmessage.AppendText(tokens[1].Trim());                        allmessage.AppendText("加入聊天室" + "\r\n");                        string newcome = tokens[1].Trim(new char[] {\r,\n});     //新增用户                         listBox1.Items.Add(newcome);                                 //在列表增加名称                        break;                    case "LEAVE":                        allmessage.AppendText(time + "  ");                        allmessage.AppendText(tokens[1].Trim());                        allmessage.AppendText("退出了聊天室" + "\r\n");                        string leaver = tokens[1].Trim(new char[] { \r,\n});                        for (int n = 0; n < listBox1.Items.Count; n++)                        {                            if (listBox1.Items[n].ToString().CompareTo(leaver) == 0) //匹配  去除相关项                            {                                listBox1.Items.RemoveAt(n);                                                         break;                            }                        }                        break;                    case "QUIT":                        m_ns.Close();                                             m_clientSocket.Close();                        m_isConnected = false;                        alive = false;                                           this.Text = "服务器断开";                        button2.Enabled = false;                        button1.Text = "连接";                        listBox1.Items.Clear();                        MessageBox.Show("服务器断开!");                        break;                }            }
View Code

这里还是给出下载链接,源程序可能还需要修改   http://download.csdn.net/detail/zhoupeng39/8104695  

http://download.csdn.net/detail/zhoupeng39/8104687

上面的程序是我从网上看到然后修改的,TCP部分就差不多了,下面说说UDP部分。

UDP就相对简单了,主要是广播和单播,当然还必须加上和TCP差不多的协议头来区分操作。

代码如下

 if (state==1)        message = string.Format("Online|{0}", m_UserName);  //1 表示上线 else        message = string.Format("Outline|{0}", m_UserName); //0 表示下线  byte[] messageByte = Encoding.Unicode.GetBytes(message);   m_BroSendClient.Send(messageByte, messageByte.Length, m_BroEndPoint);   //广播  m_BroSendClient.Close();
View Code

 

 IPEndPoint RemotePoint = new IPEndPoint(IPAddress.Any, 0);            while(true)            {                byte[] receiveByte = m_UdpRecClient.Receive(ref RemotePoint);                string receiveMessage = Encoding.Unicode.GetString(receiveByte);                string[] tokens = receiveMessage.Split(new char[] { | });        //分离字符串                string sendmessage;                switch(tokens[0])                {                    case "Online":                         //上线消息                           if (tokens[1] != m_UserName)       //开始全网广播                         {                            for (int i = 0; i < m_OtherUserName.Length; i++)                            {                                if (m_OtherUserName[i] == tokens[1])                                {                                    m_OtherUserState[i] = 1;                             //改变状态                                    m_OtherUserIp[i] = RemotePoint.Address.ToString();   //存储IP                                    ShowOnlineWindowMehtod(tokens[1]);                   //显示上线窗口                                      sendmessage = string.Format("Inline|{0}", m_UserName);                                    UdpSendMessage(sendmessage, i);                      //发送在线消息                                    break;                                }                            }                        }                        break;                     case "Inline":                                                       //在线消息                        for (int i = 0; i < m_OtherUserName.Length; i++)                        {                              if (m_OtherUserName[i]==tokens[1])                              {                                  m_OtherUserState[i] = 1;                                     m_OtherUserIp[i] = RemotePoint.Address.ToString();     //存储IP                                  break;                                  }                        }                        break;                     case "Outline":                                                      //离线消息                         for (int i = 0; i < m_OtherUserName.Length; i++)                        {                            if (m_OtherUserName[i] == tokens[1])                            {                                m_OtherUserState[i] = 0;                                m_OtherUserIp[i] = "";                                                         break;                            }                        }                        break;                                     case "Connect":                                              //请求TCP连接消息  客户端接收                         for (int i = 0; i < m_OtherUserName.Length; i++)                              {                                if (m_OtherUserName[i] == tokens[1])                                {                                    TcpClient s= new TcpClient(m_OtherUserIp[i], int.Parse(tokens[2]));                                       m_ServerCliListocket=s;                                    m_IsInChatting[i] = 1;                                    m_ClientRecIndex=i;                                    m_ClientRecThread = new Thread(new ThreadStart(RecClient));                                       m_ClientRecThread.Start();                                    break;                                }                             }                                              break;                }            }
View Code

其实在使用TCP和UDP写程序的时候困难的不是接口的调用,困难的是线程如何分配,如何管理这些线程。

在编写过程中我遇到一个问题,我是在子线程里面显示上线提示窗口,结果窗口假死,这是子线程结束窗口资源就会被回收导致的,解决的方法也很简单,就是通过

委托将显示窗口挂到主线程上面,这样窗口就不会假死了

代码如下

       void ShowOnlineWindowMehtod(string name)        {            //委托到主窗体线程上             this.Invoke(new ShowOtherUserOnlineHandle(ShowOtherUserOnline), name);        }        delegate void ShowOtherUserOnlineHandle(string name);        private void ShowOtherUserOnline(string name)        {            Online formOnline = new Online(name);            formOnline.Show(this);        }
View Code

想想编写的整个过程,我是想到哪儿就写到哪儿,之前没有设计好整个的布局,导致最终代码错误很多,代码也是乱成一块,很不美观,等考试之后我会给这个程序加上发送图片和文件的功能,然后重写整个的框架,到时再发代码。

 

C#作业总结 (5)