利用C#編寫的網絡聊天程序

1、程序分爲服務器端和客戶端;

2、任何一個客戶,均可以與服務器進行通信;

3、服務器端能及時顯示已連接的客戶端狀態,然後將之告知給所有的客戶端;

4、客戶與服務器連接成功以後,可以與任何一個其他用戶進行聊天通訊;

5、客戶如果退出程序,服務器要將之告知其他的客戶。


一、服務器的設計與編程。

服務器的設計界面如下所示

服務器端的代碼如下所示:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//添加的命名空間
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class MainForm : Form
    {
        //用來保存連接的用戶
        private List<User> userList = new List<User>();
        //使用本機的IP地址
        IPAddress localAddress;
        //定義計算機上使用的端口號
        private const int port = 51888;
        private TcpListener myListener;
        //定義一個標誌,用來判斷是否正常退出所有接受線程
        bool isNormalExit = false;
        //加載主窗體時初始化
        public MainForm()
        {
            InitializeComponent();
            listBoxStatus.HorizontalScrollbar = true;
            IPAddress[] addrIP = Dns.GetHostAddresses(Dns.GetHostName());
            localAddress = addrIP[0];
            buttonStop.Enabled = false;
        }
        //單擊監聽按鈕的處理事件
        private void buttonStart_Click(object sender, EventArgs e)
        {
            myListener = new TcpListener(localAddress, port);
            myListener.Start();
            AddItemToListBox(string.Format("開始在{0}:{1}監聽客戶連接", localAddress, port));
            //創建一個線程監聽客戶端連接請求
            Thread myThread = new Thread(ListenClientConnect);
            myThread.Start();
            buttonStart.Enabled = false;
            buttonStop.Enabled = true;
            
        }
        //接收客戶端連接
        private void ListenClientConnect()
        {
            TcpClient newClient = null;
            while (true)
            {
                try
                {
                    newClient = myListener.AcceptTcpClient();
                }
                catch
                {
                    //當單擊“停止監聽”或者退出此窗體時AcceptTcpClient()會產生異常,因此利用此異常退出循環
                    break;
                }

                User user = new User(newClient);
                Thread threadReceive = new Thread(ReceiveData);
                threadReceive.Start(user);
                userList.Add(user);
                AddItemToListBox(string.Format("[{0}]進入", newClient.Client.RemoteEndPoint));
                AddItemToListBox(string.Format("當前連接用戶數:{0}", userList.Count));
            }
        }

        private void ReceiveData(object userState)
        {
            User user = (User)userState;
            TcpClient client = user.client;
            while (isNormalExit == false)
            {
                string receiveString = null;
                try
                {
                    //從網絡流中讀出字符串,此方法會自動判斷字符串長度前綴
                    receiveString = user.br.ReadString();
                }
                catch
                {
                    if (isNormalExit == false)
                    {
                        AddItemToListBox(string.Format("與[{0}]失去聯繫,已終止接收該用戶信息", client.Client.RemoteEndPoint));
                        RemoveUser(user);
                    }
                    break;
                }
                AddItemToListBox(string.Format("來自[{0}]:{1}", user.client.Client.RemoteEndPoint, receiveString));
                string[] splitString = receiveString.Split(',');
                switch (splitString[0])
                { 
                    case "Login":
                        user.userName = splitString[1];
                        SendToAllClient(user, receiveString);
                        break;
                    case "Logout":
                        SendToAllClient(user, receiveString);
                        RemoveUser(user);
                        return;
                    case "Talk":
                        string talkString = receiveString.Substring(splitString[0].Length + splitString[1].Length + 2);
                        AddItemToListBox(string.Format("{0}對{1}說:{2}", user.userName, splitString[1], talkString));
                        SendToClient(user, "talk," + user.userName + "," + talkString);
                        foreach (User target in userList)
                        {
                            if (target.userName == splitString[1] && user.userName != splitString[1])
                            {
                                SendToClient(target, "talk," + user.userName + "," + talkString);
                                break;
                            }
                        }
                        break;
                    default:
                        AddItemToListBox("什麼意思啊:" + receiveString);
                        break;
                        
                }
            }
        }

        private void SendToClient(User user, string message)
        {
            try
            {
                //將字符串寫入網絡流,此方法會自動附加字符串長度前綴
                user.bw.Write(message);
                user.bw.Flush();
                AddItemToListBox(string.Format("向[{0}]發送:{1}", user.userName, message));
            }
            catch
            {
                AddItemToListBox(string.Format("向[{0}]發送信息失敗", user.userName));
            }
        }
        //發送信息給所有客戶,name指定發給哪個用戶,message儲存信息的內容
        private void SendToAllClient(User user, string message)
        {
            string command = message.Split(',')[0].ToLower();
            if (command == "login")
            {
                for (int i = 0; i < userList.Count; i++)
                {
                    SendToClient(userList[i], message);
                    if (userList[i].userName != user.userName)
                    {
                        SendToClient(user, "login," + userList[i].userName);
                    }
                }

            }
            else if (command == "logout")
            {
                for (int i = 0; i < userList.Count; i++)
                {
                    if (userList[i].userName != user.userName)
                    {
                        SendToClient(userList[i], message);
                    }

                }
            }
        }
        //移除用戶,user代表指定要刪除的用戶
        private void RemoveUser(User user)
        {
            userList.Remove(user);
            user.close();
            AddItemToListBox(string.Format("當前連接用戶數:{0}", userList.Count));
        }


        private delegate void AddItemToListBoxDelegate(string str);
        //想ListBox中追加狀態信息,str儲存要追加的信息
        private void AddItemToListBox(string str)
        {
            if (listBoxStatus.InvokeRequired)
            {
                AddItemToListBoxDelegate d = AddItemToListBox;
                listBoxStatus.Invoke(d, str);
            }
            else
            {
                listBoxStatus.Items.Add(str);
                listBoxStatus.SelectedIndex = listBoxStatus.Items.Count - 1;
                listBoxStatus.ClearSelected();
            }

        }
        //按下"停止監聽"按鈕的處理事件
        private void buttonStop_Click(object sender, EventArgs e)
        {
            AddItemToListBox("開始停止服務,並依次使用戶退出!");
            isNormalExit = true;
            for (int i = userList.Count - 1; i >= 0; i--)
            {
                RemoveUser(userList[i]);
            }
            myListener.Stop();
            buttonStart.Enabled = true;
            buttonStop.Enabled = false;
        }
        //關閉窗口時觸發的事件
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (myListener != null)
            {
                //引發buttonStop的Click事件
                buttonStop.PerformClick();
            }
        }
    }
}

二、客戶端的設計與編程。

客戶端的設計界面如下所示

客戶端的代碼如下所示:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//添加的命名空間
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace SyncChatClient
{
    public partial class MainForm : Form
    {
        private bool isExit = false;
        private TcpClient client;
        private BinaryReader br;
        private BinaryWriter bw;
        public MainForm()
        {
            InitializeComponent();
            Random r = new Random((int)DateTime.Now.Ticks);
            textBoxUserName.Text = "user" + r.Next(100, 999);
            listBoxOnlineStatus.HorizontalScrollbar = true;
        }
        //單擊"連接服務器"按鈕的Click事件
        private void buttonConnect_Click(object sender, EventArgs e)
        {
            buttonConnect.Enabled = false;
            try
            {
                //此處爲方便演示,實際使用時要將Dns.GetHostName()改爲服務器域名
                client = new TcpClient(Dns.GetHostName(), 51888);
                AddTalkMessage("連接成功");
            }
            catch
            {
                AddTalkMessage("連接失敗");
                buttonConnect.Enabled = true;
                return;
            }
            //獲取網絡流
            NetworkStream networkStream = client.GetStream();
            //將網絡流作爲二進制讀寫對象
            br = new BinaryReader(networkStream);
            bw = new BinaryWriter(networkStream);
            SendMessage("Login," + textBoxUserName.Text);
            Thread threadReceive = new Thread(new ThreadStart(ReceiveData));
            threadReceive.IsBackground = true;
            threadReceive.Start();
        }
        //處理接受的服務器端數據
        private void ReceiveData()
        {
            string receiveString = null;
            while (isExit == false)
            {
                try
                {
                    //從網絡流中讀出字符串
                    receiveString = br.ReadString();

                }
                catch
                {
                    if (isExit == false)
                    {
                        MessageBox.Show("與服務器失去聯繫.");
                    }
                    break;
                }
                string[] splitString = receiveString.Split(',');
                string command = splitString[0].ToLower();
                switch (command)
                { 
                    case "login":
                        AddOnline(splitString[1]);
                        break;
                    case "logout":
                        RemoveUserName(splitString[1]);
                        break;
                    case "talk":
                        AddTalkMessage(splitString[1] + ":\r\n");
                        AddTalkMessage(receiveString.Substring(splitString[0].Length + splitString[1].Length + 2));
                        break;
                    default:
                        AddTalkMessage("什麼意思啊:" + receiveString);
                        break;
                }
            }
            Application.Exit();
        }
        //向服務器端發送消息
        private void SendMessage(string message)
        {
            try
            {
                //將字符串寫入網絡流,此方法會自動附加字符串長度前綴
                bw.Write(message);
                bw.Flush();
            }
            catch
            {
                AddTalkMessage("發送失敗!");
            }
        }

        private delegate void MessageDelegate(string message);
        //在richTextBoxTalkInfo中追加聊天信息
        private void AddTalkMessage(string message)
        {
            if(richTextBoxTalkInfo.InvokeRequired)
            {
                MessageDelegate d=new MessageDelegate(AddTalkMessage);
                richTextBoxTalkInfo.Invoke(d,new Object[]{message});
            }
            else
            {
                richTextBoxTalkInfo.AppendText(message+Environment.NewLine);
                richTextBoxTalkInfo.ScrollToCaret();
            }
        }

        private delegate void AddOnlineDelegate(string message);
        //在listBoxOnlineStatus中添加在線的其他客戶端信息
        private void AddOnline(string userName)
        {
            if (listBoxOnlineStatus.InvokeRequired)
            {
                AddOnlineDelegate d = new AddOnlineDelegate(AddOnline);
                listBoxOnlineStatus.Invoke(d, new object[] { userName });
            }
            else
            {
                listBoxOnlineStatus.Items.Add(userName);
                listBoxOnlineStatus.SelectedIndex = listBoxOnlineStatus.Items.Count - 1;
                listBoxOnlineStatus.ClearSelected();
            }
        }

        private delegate void RemoveUserNameDelegate(string userName);
        //在listBoxOnlineStatus中移除不在線的其他客戶端信息
        private void RemoveUserName(string userName)
        {
            if (listBoxOnlineStatus.InvokeRequired)
            {
                RemoveUserNameDelegate d = RemoveUserName;
                listBoxOnlineStatus.Invoke(d, userName);
            }
            else
            {
                listBoxOnlineStatus.Items.Remove(userName);
                listBoxOnlineStatus.SelectedIndex = listBoxOnlineStatus.Items.Count - 1;
                listBoxOnlineStatus.ClearSelected();
            }
        }

        private void buttonSend_Click(object sender, EventArgs e)
        {
            if (listBoxOnlineStatus.SelectedIndex != -1)
            {
                SendMessage("Talk," + listBoxOnlineStatus.SelectedItem + "," + textBoxSend.Text + "\r\n");
                textBoxSend.Clear();
            }
            else
            {
                MessageBox.Show("請先在[當前在線]中選擇一個對話者");
            }
        }
        //關閉窗口時觸發的事件
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (client != null)
            {
                SendMessage("Logout," + textBoxUserName.Text);
                isExit = true;
                br.Close();
                bw.Close();
                client.Close();
            }
        }
        //在發送信息文本框中按下【Enter】鍵觸發的事件
        private void textBoxSend_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                buttonSend.PerformClick();
            }
        }

    }
}


至此,程序編寫完成。

資源下載鏈接地址:http://download.csdn.net/detail/scrystally/4730653






發佈了26 篇原創文章 · 獲贊 8 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章