• 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

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

  • 相关阅读:
    游吟诗人阿严
    学霸女
    sql group by 分组后查询最新的一条数据
    腐朽
    我喜欢不说话的山川
    redis启动
    php 时间轴,数据统计(最近7天的数据)
    php options 请求跨域
    mac关机声音
    JVM-内存模型
  • 原文地址:https://www.cnblogs.com/fightfuture/p/4163887.html
Copyright © 2020-2023  润新知