網絡編程-實驗2-C與C通信

一、實驗要求

具體要求包括:

1,Server支持多客戶訪問;

2,C與S之間使用TCP連接;

3,C與C之間直接通信(不是通過S傳遞)。

4,C與C之間直接通信既可以使用TCP,也可以使用UDP。

5,可以使用Socket,也可以使用TcpClient/UdpClient等;

6,實驗示意圖如下:        


二、實驗思路

(1)客戶端登陸服務端時,打開客戶端的監聽併發送客戶端的用戶名和端口號。

(2)客戶端發送信息時,服務端根據客戶端的用戶名返回端口號。

(3)客戶端根據服務端返回的端口號與信息接收方進行tcp通信。

(4)客戶端與客戶端通信時,不保留連接,僅在需要發送信息時建立連接。

三、應用界面

(1)服務器界面:


(2)客戶端界面(未登錄):


(3)客戶端界面(登陸):

 

(4)客戶端與客戶端互相通信:

 


 

 

(5)客戶端給多個客戶端發送消息:

 

(6)客戶端退出:

 


源碼如下:

ClientForm.cs:

using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections.Generic;
using System.Text;

namespace Client
{
    public partial class ClientForm : Form
    {
        public ClientForm()
        {
            InitializeComponent();
            UserNameList = new List();
            UserPortList = new List();
            isMessageCome = false;
            this.label_State.Text = "未檢測到服務器";
            this.FormClosing += ClientWindow_Closing;
        }
        private bool isMessageCome { get; set; }
        private bool isLogin { get; set; }
        private TcpListener listener;
        private TcpClient SocketForClient;
        private BinaryReader br_C;
        private BinaryWriter bw_C;

        private string receiveString;
        private List UserNameList { get; set; }
        private List UserPortList { get; set; }
        private TcpClient client_S;
        private NetworkStream networkStream_S;
        private BinaryReader br_S;
        private BinaryWriter bw_S;
        private IPAddress localIpAddress;
        private int remotePort;
        private string remoteHost;
        private string userName { get; set; }
        private string userPort { get; set; }
        private enum clientState
        {
            Login,
            Talk,
            Logout
        };

        private delegate void Delegate1();
        private delegate void Delegate2();

        private void ClientWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (client_S != null)
            {
                SendMessageToServer(clientState.Logout, "退出服務器。", textBox_Port.Text);
                br_S.Close();
                bw_S.Close();
                client_S.Close();
            }
        }

        private void ClientLogin()
        {
            GetHostAddress();
            remotePort = 51888;
            remoteHost = Dns.GetHostName();
            try
            {
                client_S = new TcpClient(remoteHost, remotePort);
                this.label_State.Text = "連接服務器成功。";
                NetworkStream networkStream = client_S.GetStream();
                br_S = new BinaryReader(networkStream);
                bw_S = new BinaryWriter(networkStream);
                Thread threadReceive = new Thread(ReceiveDataFromServer);
                threadReceive.IsBackground = true;
                threadReceive.Start();
                UpdateClientForm();

                //打開監聽器
                listener = new TcpListener(localIpAddress, Convert.ToInt16(userPort));
                listener.Start();
                Thread thread_for_listener = new Thread(ReceiveClient);
                thread_for_listener.IsBackground = true;
                thread_for_listener.Start();

            }
            catch
            {
                //MessageBox.Show(ex.ToString());
                this.label_State.Text = "服務器尚未啓動,連接服務器失敗。";
                return;
            }
        }
        //接收客戶端與客戶端之間的連接
        private void ReceiveClient()
        {
            receiveString = null;
            while (true)
            {
                try
                {
                    //MessageBox.Show("8", DateTime.Now.ToString());
                    SocketForClient = listener.AcceptTcpClient();
                    networkStream_S = SocketForClient.GetStream();
                    bw_C = new BinaryWriter(networkStream_S);
                    br_C = new BinaryReader(networkStream_S);
                    receiveString = br_C.ReadString();
                    //MessageBox.Show(receiveString, this.userName);
                    if (receiveString != null)
                    {
                        Delegate1 d1 = new Delegate1(AddInfo_C);
                        textBox_ReceivedMessage.Invoke(d1);
                    }
                    br_C.Close();
                    bw_C.Close();
                    networkStream_S.Close();
                    SocketForClient.Close();
                }
                catch
                {
                    break;
                }
            }
        }

        //從服務器接收數據
        private void ReceiveDataFromServer()
        {
            receiveString = null;
            while (true)
            {
                try
                {
                    receiveString = br_S.ReadString();
                    //MessageBox.Show("5", DateTime.Now.ToString());
                    if (isUserInfo(receiveString))
                    {
                        //更新在線用戶列表
                        this.UserNameList.Clear();
                        string[] s = receiveString.Split(',');
                        for (int i = 0; i < s.Length - 1; i++)
                        {

                            if (s[i] != this.userName)
                            {
                                UserNameList.Add(s[i]);
                            }
                        }
                        Delegate2 d2 = new Delegate2(AddUserToList);
                        this.listBox_UserName.Invoke(d2);
                    }
                    else if (isUserPort(receiveString))
                    {
                        this.UserPortList.Clear();
                        string[] s = receiveString.Split(',');
                        int count = Convert.ToInt32(s[0]);
                        for (int i = 0; i < count; i++)
                        {
                            if (s[i + 1] != this.userPort)
                            {
                                UserPortList.Add(s[i + 1]);
                            }
                        }

                        string message = "";
                        for (int i = count + 1; i < s.Length - 1; i++)
                        {
                            message += s[i];
                        }
                        //MessageBox.Show(message);
                        for (int i = 0; i < UserPortList.Count; i++)
                        {
                            //MessageBox.Show(UserPortList.Count.ToString());
                            SendMessageToClient(UserPortList[i], message);
                        }
                        
                    }
                    else
                    {
                        if (textBox_ReceivedMessage.InvokeRequired)
                        {
                            Delegate1 d1 = new Delegate1(AddInfo_S);
                            textBox_ReceivedMessage.Invoke(d1);
                        }
                    }
                }
                catch
                {
                    break;
                }
            }
        }

        //添加信息到面板中
        private void AddInfo_S()
        {
            textBox_ReceivedMessage.Text += DateTime.Now.ToString() + " Server:" + receiveString + "\r\n";
        }
        private void AddInfo_C()
        {
            string[] s = receiveString.Split(',');
            StringBuilder sb = new StringBuilder();
            for (int i = 1; i < s.Length; i++)
            {
                sb.Append(s[i]);
            }
            textBox_ReceivedMessage.Text += DateTime.Now.ToString() + " " + s[0] + ":" + sb.ToString() + "\r\n";
        }
        //添加信息到在線用戶面板中
        private void AddUserToList()
        {
            this.listBox_UserName.Items.Clear();
            foreach (string name in UserNameList)
            {
                this.listBox_UserName.Items.Add(name);
            }
        }

        //判斷是否是用戶信息
        private bool isUserInfo(string receiveString)
        {
            string[] s = receiveString.Split(',');
            if (s[s.Length - 1] == "@UserName")
            {
                return true;
            }
            return false;
        }
        //判斷是否是用戶端口號
        private bool isUserPort(string receiveString)
        {
            string[] s = receiveString.Split(',');
            if (s[s.Length - 1] == "@UserPort")
            {
                return true;
            }
            return false;
        }

        //發送狀態和信息
        //重載1,啓動狀態和離開狀態
        private void SendMessageToServer(clientState state, string message, string port)
        {
            try
            {
                if (message != "" && port != "")
                {
                    switch (state)
                    {
                        case clientState.Login:
                            bw_S.Write("Login," + textBox_UserName.Text + "," + port);
                            break;
                        case clientState.Logout:
                            bw_S.Write("Logout," + message);
                            break;
                        default:
                            break;
                    }
                    bw_S.Flush();

                }

            }
            catch { return; }
        }
        //重載2,交流狀態
        private void SendMessageToServer(clientState state, List list, string message)
        {
            try
            {
                if (clientState.Talk == state && list.Count > 0 && message != "")
                {
                    //MessageBox.Show("2", DateTime.Now.ToString());
                    bw_S.Write("Talk," + GetUserNameFromListBox(list) + message);
                    bw_S.Flush();
                }
            }
            catch { return; }
        }

        //獲取需要列表中選中的用戶名
        private string GetUserNameFromListBox(List list)
        {
            string names = "";
            int i = list.Count;
            names = i.ToString() + ",";
            foreach (string name in list)
            {
                names += name + ",";
            }
            return names;
        }
        public void UpdateClientForm()
        {
            this.textBox_IPAddress.Text = localIpAddress.ToString();
            this.userName = textBox_UserName.Text;
            this.userPort = textBox_Port.Text;
        }

        private void GetHostAddress()
        {
            IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
            foreach (var v in ips)
            {
                if (v.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIpAddress = v;
                    break;
                }
            }
        }

        //判斷信息傳送對象
        private List GetListBoxSelectedItems(ListBox listBox_UserName)
        {
            List list = new List();
            for (int i = 0; i < listBox_UserName.SelectedItems.Count; i++)
            {
                list.Add(listBox_UserName.SelectedItems[i].ToString());
            }
            return list;
        }
        private void btn_SendMessage_Click(object sender, EventArgs e)
        {
            if (isLogin)
            {
                //MessageBox.Show("1", DateTime.Now.ToString());
                SendMessageToServer(clientState.Talk, GetListBoxSelectedItems(this.listBox_UserName), this.textBox_SendMessage.Text);
                textBox_SendMessage.Clear();
            }
        }
        //根據端口號發送信息
        private void SendMessageToClient(string userPort, string message)
        {
            try
            {
                //MessageBox.Show("7", DateTime.Now.ToString());
                TcpClient c = new TcpClient(remoteHost, Convert.ToInt32(userPort));
                NetworkStream networkStream = c.GetStream();
                BinaryWriter bw = new BinaryWriter(networkStream);
                BinaryReader br = new BinaryReader(networkStream);
                bw.Write(this.userName + "," + message);
                bw.Flush();
                bw.Close();
                br.Close();
                networkStream.Close();
                c.Close();
                //MessageBox.Show("關閉流");
            }
            catch
            {
                MessageBox.Show("error 01");
            }
        }

        private void btn_Login_Click(object sender, EventArgs e)
        {
            if (textBox_UserName.Text != "" && textBox_Port.Text != "")
            {
                ClientLogin();
                SendMessageToServer(clientState.Login, userName, userPort);
                textBox_UserName.Enabled = false;
                textBox_Port.Enabled = false;
                btn_Login.Enabled = false;
                isLogin = true;
            }
        }

        private void ClientForm_Load(object sender, EventArgs e)
        {

        }
    }
}

ServerForm.cs :

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using Client;

namespace Server
{

    public partial class ServerForm : Form
    {

        //Variables6
        public static IPAddress localIpAddress;
        public static int port = 51888;
        private TcpListener myListener;
        private TcpClient SocketForClient;
        private NetworkStream networkStream;
        private Thread myThread;
        private string message;
        private delegate void delegate1();
        private delegate void delegate_AddInfo();

        //Attributes

        //Functions
        public ServerForm()
        {
            InitializeComponent();
            this.Closing += ThreadServer_Closing;
            try
            {
                GetHostAddress();
                UpdateServerForm();
                OpenTcpListener();
                OpenOtherListener();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                MessageBox.Show("服務器初始化失敗", "提示");
            }

        }

        //後臺檢測需不需要更新面板
        private void UpdateInfoListener()
        {
            while (true)
            {
                while (CC.updated == true)
                {
                    delegate1 d = new delegate1(UpdateClientList);
                    this.dataGridView1.Invoke(d);
                    CC.updated = false;
                }
            }
        }

        //後臺檢測功能
        private void OpenOtherListener()
        {
            Thread messageListener = new Thread(MessageListener);
            messageListener.IsBackground = true;
            messageListener.Start();
            Thread updateInfoListener = new Thread(UpdateInfoListener);
            updateInfoListener.IsBackground = true;
            updateInfoListener.Start();
        }

        //後臺檢測是否有信息需要輸出到message面板中
        private void MessageListener()
        {
            while (true)
            {
                while (CC.messageQueue.Count > 0)
                {
                    message = CC.messageQueue.Dequeue();
                    delegate_AddInfo delegate1 = new delegate_AddInfo(AddInfo);
                    textBox_ReceivedMessage.Invoke(delegate1);
                }
            }
        }
        private void AddInfo()
        {
            this.textBox_ReceivedMessage.Text += message + "\r\n";
        }

        //獲取本機地址
        private void GetHostAddress()
        {
            IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());
            foreach (var v in ips)
            {
                if (v.AddressFamily == AddressFamily.InterNetwork)
                {
                    localIpAddress = v;
                    break;
                }
            }
        }

        //更新服務器面板部分信息
        public void UpdateServerForm()
        {
            this.textBox_IPAddress.Text = localIpAddress.ToString();
            this.textBox_Port.Text = port.ToString();
        }

        //開啓tcp監聽器
        private void OpenTcpListener()
        {
            try
            {
                myListener = new TcpListener(localIpAddress, port);
                myListener.Start();
                label_State.Text = string.Format("開始在{0}:{1}監聽客戶連接", localIpAddress, port);
                myThread = new Thread(ListenClientConnection);
                myThread.IsBackground = true;
                myThread.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                label_State.Text = "服務器啓動監聽失敗,請嘗試重新啓動。";
            }
        }

        //tcp監聽器
        private void ListenClientConnection()
        {
            while (true)
            {
                try
                {
                    SocketForClient = myListener.AcceptTcpClient();
                    networkStream = SocketForClient.GetStream();
                    User user = new User(SocketForClient);
                    CC.userList.Add(user);
                    user.ReceiveData();
                    delegate1 d = new delegate1(UpdateClientList);
                    this.dataGridView1.Invoke(d);
                    CC.SendToClient(user, "Hello!");
                }
                catch
                {
                    break;
                }
            }
        }

        //客戶端關閉的時候
        private void ThreadServer_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (myListener != null)
            {
                if (SocketForClient != null)
                {
                    SocketForClient.Close();
                    networkStream.Close();
                }
                myListener.Stop();
                this.label_State.Text = "服務器已關閉";
            }
        }

        //添加在線用戶到數組中
        private void AddClientToCC()
        {
            CC.Count = 0;
            foreach (DataGridViewRow dr in this.dataGridView1.Rows)
            {
                CC.Count++;
            }
            CC.Count--;
            int i = 0;
            foreach (DataGridViewRow dr in this.dataGridView1.Rows)
            {
                if (i < CC.Count)
                {
                    CC.userNamePort[i, 0] = dr.Cells[0].Value.ToString();
                    CC.userNamePort[i, 1] = dr.Cells[1].Value.ToString();
                    i++;
                }
            }
        }

        //更新客戶端列表
        private void UpdateClientList()
        {
            if (CC.userList.Count > 0)
            {
                try
                {
                    this.dataGridView1.Rows.Clear();
                    System.Threading.Thread.Sleep(1000);
                    //創建表的行,並與表相關聯。
                    foreach (User user in CC.userList)
                    {
                        DataGridViewRow dr = new DataGridViewRow();
                        dr.CreateCells(dataGridView1);
                        dr.Cells[0].Value = user.UserName;
                        dr.Cells[1].Value = user.UserPort;
                        this.dataGridView1.Rows.Add(dr);
                    }
                    AddClientToCC();
                    //發送消息給所有客戶端以更新用戶列表信息
                    CC.UpdateClientList(CC.userList);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                this.dataGridView1.Rows.Clear();
            }
        }

        //發送消息的按鈕事件
        private void btn_SendMessage_Click(object sender, EventArgs e)
        {
            if (this.textBox_SendMessage.Text != "")
            {
                string sendMessage = this.textBox_SendMessage.Text;
                List selectedUser = new List();
                foreach (User user in CC.userList)
                {
                    //遍歷選中的行對象
                    foreach (DataGridViewRow dr in this.dataGridView1.SelectedRows)
                    {
                        //判斷是否存在於user列表中
                        if (dr.Cells[0].Value.ToString() == user.UserName && dr.Cells[1].Value.ToString() == user.UserPort)
                        {
                            selectedUser.Add(user);
                            break;
                        }
                    }
                }
                CC.SendToClient(selectedUser, sendMessage);
                this.textBox_SendMessage.Text = "";
            }
        }
        //創建客戶端
        private void btn_CreateClient_Click(object sender, EventArgs e)
        {
            ClientForm cForm = new ClientForm();
            cForm.Show();
        }

        private void ServerForm_Load(object sender, EventArgs e)
        {

        }

        private void btn_Flush_Click(object sender, EventArgs e)
        {
            UpdateClientList();
        }
    }
}

CC.cs:

using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Server
{
    public class CC
    {
        public static List userList { get; set; }
        public static Queue messageQueue { get; set; }
        public static Dictionary Users { get; set; }
        public static bool updated { get; set; }
        public static string[,] userNamePort { get; set; }
        public static int Count { get; set; }
        static CC()
        {
            userList = new List();
            userNamePort = new string[100,2];
            messageQueue = new Queue();
            Users = new Dictionary();
        }

        public static void SendToServer(string message)
        {
            messageQueue.Enqueue(message);
        }

        public static void RemoveUser(User user)
        {
            userList.Remove(user);
        }

        public static void SendToClient(List selectedUser, string message)
        {
            foreach (User user in selectedUser)
            {
                user.bw.Write(message);
                user.bw.Flush();
            }
        }

        public static void SendToClient(User selectedUser, string message)
        {
            //MessageBox.Show("4", DateTime.Now.ToString());
            selectedUser.bw.Write(message);
            selectedUser.bw.Flush();
        }

        //更新用戶信息列表
        public static void UpdateClientList(List selectedUser)
        {
            string info = "";
            foreach (User user in selectedUser)
            {
                info += user.UserName + ",";
            }
            info += "@UserName";
            foreach (User user in selectedUser)
            {
                user.bw.Write(info);
                user.bw.Flush();
            }
        }

        internal static void SendToClient(string message)
        {
            throw new NotImplementedException();
        }
    }
}

User.cs:
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Server
{
    public class User
    {
        public BinaryReader br { get; private set; }
        public BinaryWriter bw { get; private set; }
        public string receiveString { get; set; }
        public bool isRead { get; set; }
        private TcpClient client;
        private NetworkStream networkStream;
        private Thread IOThread;
        private delegate void delegateAddInfo();
        private string mmessage;
        public string UserName;
        public string UserPort;

        public User(TcpClient client)
        {
            this.client = client;
            networkStream = client.GetStream();
            br = new BinaryReader(this.networkStream);
            bw = new BinaryWriter(this.networkStream);
        }

        public void ReceiveData()
        {
            IOThread = new Thread(ReceiveFromClient);
            IOThread.Start();
        }
        //接收信息
        private void ReceiveFromClient()
        {
            while (true)
            {
                receiveString = null;
                try
                {
                    receiveString = br.ReadString();
                }
                catch
                {
                    CC.RemoveUser(this);
                    return;
                }
                string[] split = receiveString.Split(',');
                switch (split[0])
                {
                    case "Login":
                        UserName = split[1];
                        UserPort = split[split.Length - 1];
                        mmessage = DateTime.Now.ToString() + " " + UserName + "[" + UserPort + "]" + "成功連接服務器。";
                        break;
                    case "Talk":
                        mmessage = DateTime.Now.ToString() + " " + UserName + "[" + UserPort + "]" + GetMessage(receiveString);
                        break;
                    case "Logout":
                        mmessage = DateTime.Now.ToString() + " " + UserName + "[" + UserPort + "]" + "已與服務器斷開。";
                        //刪除並更新面板

                        CC.RemoveUser(this);
                        CC.updated = true;
                        CC.UpdateClientList(CC.userList);
                        break;
                    default:
                        break;
                }
                CC.SendToServer(mmessage);
            }
        }
        //處理信息中的用戶信息,查看轉發對象。
        private List SendMessageToWho(string receiveString)
        {
            List users = new List();
            string[] s = receiveString.Split(',');
            try
            {
                int number = Convert.ToInt32(s[1]);
                if (number > 0)
                {

                    for (int i = 0, j = 2; i < number; i++, j++)
                    {
                        users.Add(s[j]);
                    }
                }
                return users;
            }
            catch { return null; }
        }
        //處理信息
        private string GetMessage(string receviceString)
        {
            //MessageBox.Show("3", DateTime.Now.ToString());
            string[] s = receviceString.Split(',');
            StringBuilder sb = new StringBuilder();
            StringBuilder sb_Return = new StringBuilder();
            List list = SendMessageToWho(receiveString);
            sb.Append("向");
            sb_Return.Append(list.Count.ToString() + ",");
            for (int i = 0; i < list.Count; i++)
            {
                sb.Append(list[i] + ",");
                sb_Return.Append(GetUserPort(list[i]) + ",");
            }
            sb.Append("發送了消息:");
            for (int i = list.Count + 2; i < s.Length; i++)
            {
                sb.Append(s[i]);
                sb_Return.Append(s[i]);
            }
            sb_Return.Append(",@UserPort");
            CC.SendToClient(this,sb_Return.ToString());
            return sb.ToString();
        }

        private string GetUserPort(string UserName)
        {
            for(int i = 0;i




 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章