網絡編程之即時通信程序(聊天室)------(四)客戶端搭建


       上一節我們搭建了即時通信程序的登錄端,這一節我們要實現即時通信程序的主客戶端的搭建,也就是聊天、發文件端的創建。講完這一節之后,我們就可以自己實現一個即時通信程序了。好了,先上一個圖。 

 

UI布局如下:有一個ListBox用來顯示當前在線用戶命名為onLineList

               三個文本框分別為:txtchatContenttxtsendMsgtxtsendFile,分別表示:聊天的記錄、發送信息框、要發送的文件框

               四個按鈕分別為:btnsendMsgbtnsendAllbutton1button2,分別表示:

發送消息、群發消息、選擇要發送的文件、發送文件

下面我們通過具體的示例來向大家一步步的進行講解。

首先需要創建以下全局變量:

       

        private ClientLogin clientLogin;//用來存儲從ClientLogin傳過來的client參數
        private string ClientName;//表示當前的用戶名
        private TcpClient tcpClient;//全局的TcpClient對象,用來負責客戶端的連接、通信
        private NetworkStream netStream;//全局的NetworkStream對象,負責發送、接受信息

接着,我們需要在構造函數里做如下處理:

public ChatClient(ClientLogin clogin)
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;//取消跨線程檢測,允許非UI線程操作UI元素
            skinEngine1.SkinFile = "SteelBlack.ssk";//加載皮膚文件 
            clientLogin = clogin;//將從登陸框傳入的參數賦值給clientLogin
            lbname.Text += clientLogin.LoginName;
            tcpClient = clogin.TCPClient;將從登陸框傳入的clogin的TCPClient屬性賦值給全局tcpClient,負責客戶端的通信
            if (tcpClient != null)
            {
                netStream = tcpClient.GetStream();
                txtchatContent.Text = "連接成功!\r\n";
                Thread listenThread = new Thread(new ThreadStart(Listening));//專門啟動一個線程負責與服務端溝通
                listenThread.Start();
            }

我們在Listening函數中來處理具體監聽操作,我們在第一節中已經定制了客戶端的通信,在Listening函數里有用到,在這里我們再溫習一下。

1、先判斷接收到的第一個字節是否為0,如果為0則直接保存為文件,如果不為0,則進行如下的判斷。

2、接收到的第一個字節不為0,即收到的信息為字符串。

2.1、如果接收到的字符串格式為“OnLine|登錄用戶名|”,則顯示登錄用戶名

2.2、如果接受到的字符串格式為“Off|用戶名1、用戶名2、用戶名3.....|”,如果有用戶登錄或者離開則更新在線用戶列表

2.3、如果收到的為其他格式的字符串,則直接添加在聊天窗口里,顯示聊天信息。

 public void Listening()
        {
            int length=0;
            while (true)
            {   //先創建一個10M的緩存區
                byte[] Msg = new byte[1024 * 1024 * 10];
                //將傳輸的流讀取到該緩沖區中
                length=netStream.Read(Msg, 0, Msg.Length);
                //如果緩沖區的第一字節為0則為文件,否則,則為消息 
                if (Msg[0] == 0)
                {      //直接新建一個文件流保存傳輸過來的文件
                    SaveFileDialog sfDialog = new SaveFileDialog();
                    if (sfDialog.ShowDialog() == DialogResult.OK)
                    {
                        FileStream fs = new FileStream(sfDialog.FileName, FileMode.OpenOrCreate, FileAccess.Write);
                        fs.Write(Msg, 1, length - 1);
                        MessageBox.Show("文件傳輸完畢!");
                    }
                }
                else
                {
                    //第一個字節不為0,肯定為消息字符串
                    string msg = Encoding.Default.GetString(Msg);
                    string[] results = msg.Split(new char[] { '|' });
                    if (results[0]=="OnLine")//如果有人上線,則顯示上線人姓名
                    {
                        txtchatContent.Text += results[1]+"\r\n";
                    }
                    else if (results[0] == "Off")//有人上線或離開,更新在線人員列表
                    {
                        string[] clients = results[1].Split(new char[] { '、' });
                        onlineList.Items.Clear();
                        for (int i = 0; i < clients.Length-1; i++)
                        {
                            onlineList.Items.Add(clients[i]);       
                        }
                    }
                    else
                    {
                        txtchatContent.Text += msg+"\r\n";
                    }
                }
            }
        }

 接受我們需要在btnsendMsg按鈕的Click事件的處理函數做如下處理:

需要將發送的消息做特殊的處理,發送信息的格式為:MSG|接受者姓名|發送者姓名|發送內容|

在發送信息前,要選擇要發送的用戶,如果沒有選擇用戶則不能進行發送信息。

private void btnsendMsg_Click(object sender, EventArgs e)
        {
            if (onlineList.SelectedItem!=null)
            {
                if (!string.IsNullOrEmpty(txtsendMsg.Text))
                {
                    try
                    {
                        string msg ="MSG|"+ onlineList.SelectedItem.ToString() + "|"+clientLogin.LoginName+"|" + txtsendMsg.Text+"\r\n|";
                        byte[] buffer = Encoding.Default.GetBytes(msg);
                        this.netStream.Write(buffer, 0, buffer.Length);
                    }
                    catch (Exception e2)
                    {
                        MessageBox.Show("信息發送異常:" + e2.Message);
                    }
                }
                else
                {
                    MessageBox.Show("要發送的信息不能為空!");
                }
            }
            else
            {
                MessageBox.Show("請選擇要發送的對象!");
            }
        }

如果我們需群發信息,則直接點擊群發信息按鈕就可以了,所以我們在btnSendAll按鈕中做如下處理,將需要群發的信息進行加工,信息格式為:MSG|發送者姓名|發送內容|

 

        private void btnsendAll_Click(object sender, EventArgs e)
        {
            string msg = "MSGALL|"+clientLogin.LoginName+"|" + txtsendMsg.Text+"\r\n|";
            byte[] buffer = Encoding.Default.GetBytes(msg);
            this.netStream.Write(buffer, 0, buffer.Length);
        }

 如果我們需要發送文件,則需要先選擇要發送的文件,所以在button1Click事件的處理函數中做如下處理,選擇要發送的文件(文件大小不能超過10M

      private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofDialog = new OpenFileDialog();
            if (ofDialog.ShowDialog() == DialogResult.OK)
            {
               FileInfo f = new FileInfo(ofDialog.FileName);
                if (f.Length < 1024 * 1224 * 10)
                {
                    txtsendFile.Text = ofDialog.FileName;
                }
                else
                {
                    MessageBox.Show("不好意思!您傳輸的文件大於10M,請分割后再傳!");
                }

  選擇文件后就可以點擊發送,在button2Click事件的處理函數中做如下處理,將要發送的文件讀取到字節數組中,但是需要將該字節數組的首字節設置為0,然后才進行發送。

具體代碼如下:

private void button2_Click(object sender, EventArgs e)
        {
            byte[] buffer = new byte[1024 * 1024 * 10];
            try
            {
                FileStream fs = new FileStream(txtsendFile.Text, FileMode.Open, FileAccess.Read);
                int length = fs.Read(buffer, 0, buffer.Length);
                byte[] buffers=new byte[length+1];
                buffers[0] = 0;
                //將bytes里的數據從第0個開始拷貝到filetype里,從第一個位置開始,一共拷貝length個數據
                Buffer.BlockCopy(buffer, 0, buffers, 1, length);
                this.netStream.Write(buffers, 0, buffers.Length);
                FileStream fsq = new FileStream(@"D:\1.txt", FileMode.Create, FileAccess.Write);
                fsq.Write(buffers, 0,length+1);
                fsq.Close();
            }
            catch (Exception e2)
            {
                MessageBox.Show("文件傳輸異常:" + e2.Message);
            }
        }   
            }
        }

好了到這里我們已經完成了整個即時通信程序的設計和實現,希望可以讓大家對.NET平台下網絡通信有新的認識,也希望能夠對大家有所幫助。這個通信程序里我們主要用到的知識要點有TCP/UDP 通信(TCPListener/TCPClient)Socket套接字、多線程、文件的操作等。如果有對以上知識點不清楚的朋友可以參看我以前寫的相關的文章,希望可以對大家有所幫助。好了這一系列的文章就到這里了。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM