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()+"
";              //发送其他客户端的名称给新的客户  初始化客户列表
                                    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 + " 
"); 
                        allmessage.AppendText(tokens[2]);                            //增加消息内容
                        break;
                    case "JOIN":
                        allmessage.AppendText(time + "  ");                          
                        allmessage.AppendText(tokens[1].Trim());
                        allmessage.AppendText("加入聊天室" + "
");
                        string newcome = tokens[1].Trim(new char[] {'
','
'});     //新增用户 
                        listBox1.Items.Add(newcome);                                 //在列表增加名称
                        break;
                    case "LEAVE":
                        allmessage.AppendText(time + "  ");
                        allmessage.AppendText(tokens[1].Trim());
                        allmessage.AppendText("退出了聊天室" + "
");
                        string leaver = tokens[1].Trim(new char[] { '
','
'});
                        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

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

原文地址:https://www.cnblogs.com/fightfuture/p/4163887.html