C# winform實現一個服務端和多個客戶端進行通信


參看此鏈接http://www.cnblogs.com/longwu/archive/2011/08/25/2153636.html

在上述代碼的基礎上進行了修改,包括一些捕獲異常以及按鈕的應用,擴充了一個listbox確保服務端可以選擇和不同的客戶端進行通信

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.Threading;
using System.Net.Sockets;
using System.Net;
using System.Collections;
namespace chat1
{
    
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            StartPosition = FormStartPosition.CenterScreen;

            //關閉對文本框的非線程操作檢查
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }
        string RemoteEndPoint;     //客戶端的網絡結點

        Thread threadwatch = null;//負責監聽客戶端的線程
        Socket socketwatch = null;//負責監聽客戶端的套接字
        //創建一個和客戶端通信的套接字
        Dictionary<string, Socket> dic = new Dictionary<string, Socket> { };   //定義一個集合,存儲客戶端信息

        


        private void button1_Click(object sender, EventArgs e)
        {
            this.button1.Enabled = false;
            //定義一個套接字用於監聽客戶端發來的消息,包含三個參數(IP4尋址協議,流式連接,Tcp協議)
            socketwatch = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

            //服務端發送信息需要一個IP地址和端口號
            IPAddress address = IPAddress.Parse(textBox1.Text.Trim());//獲取文本框輸入的IP地址

            //將IP地址和端口號綁定到網絡節點point上
            IPEndPoint point = new IPEndPoint(address,int.Parse(textBox2.Text.Trim()));//獲取文本框上輸入的端口號
            //此端口專門用來監聽的

            //監聽綁定的網絡節點
            socketwatch.Bind(point);

            //將套接字的監聽隊列長度限制為20
            socketwatch.Listen(20);

            

            //創建一個監聽線程
            threadwatch = new Thread(watchconnecting);   


           
            //將窗體線程設置為與后台同步,隨着主線程結束而結束
            threadwatch.IsBackground = true;  
 
           //啟動線程   
            threadwatch.Start(); 
  
           //啟動線程后 textBox3文本框顯示相應提示
           textBox3.AppendText("開始監聽客戶端傳來的信息!" + "\r\n");
          


        }

        void OnlineList_Disp(string Info)
        {
            listBoxOnlineList.Items.Add(Info);   //在線列表中顯示連接的客戶端套接字
        }


        
        //監聽客戶端發來的請求
        private void watchconnecting()
        {
            Socket connection = null;
            while (true)  //持續不斷監聽客戶端發來的請求   
            {
                try  
                {   
                    connection = socketwatch.Accept();  
                }   
                catch (Exception ex)   
                {  
                    textBox3.AppendText(ex.Message); //提示套接字監聽異常   
                    break;   
                 }
                //獲取客戶端的IP和端口號
                IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
                int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;

                //讓客戶顯示"連接成功的"的信息
                string sendmsg = "連接服務端成功!\r\n" + "本地IP:" + clientIP + ",本地端口" + clientPort.ToString();
                byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg); 
                connection.Send(arrSendMsg);


                RemoteEndPoint = connection.RemoteEndPoint.ToString(); //客戶端網絡結點號
                textBox3.AppendText("成功與" + RemoteEndPoint + "客戶端建立連接!\t\n");     //顯示與客戶端連接情況
                dic.Add(RemoteEndPoint, connection);    //添加客戶端信息

                OnlineList_Disp(RemoteEndPoint);    //顯示在線客戶端

                
                //IPEndPoint netpoint = new IPEndPoint(clientIP,clientPort);
                
                IPEndPoint netpoint = connection.RemoteEndPoint as IPEndPoint;
                
                //創建一個通信線程    
                ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
                Thread thread = new Thread(pts);   
                thread.IsBackground = true;//設置為后台線程,隨着主線程退出而退出   
                //啟動線程   
                thread.Start(connection);   
            }   
        }

  
  

        ///   
        /// 接收客戶端發來的信息    
        ///   
        ///客戶端套接字對象  
        private void recv(object socketclientpara)
        {
            
            Socket socketServer = socketclientpara as Socket;
            while (true)   
            {   
                //創建一個內存緩沖區 其大小為1024*1024字節  即1M   
                byte[] arrServerRecMsg = new byte[1024 * 1024];   
                //將接收到的信息存入到內存緩沖區,並返回其字節數組的長度  
                try
                {
                    int length = socketServer.Receive(arrServerRecMsg);

                    //將機器接受到的字節數組轉換為人可以讀懂的字符串   
                    string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
                    
                    //將發送的字符串信息附加到文本框txtMsg上   
                    textBox3.AppendText("客戶端:" + socketServer.RemoteEndPoint+",time:" + GetCurrentTime() + "\r\n" + strSRecMsg + "\r\n\n");
                }
                catch (Exception ex)
                {
                    textBox3.AppendText("客戶端"+socketServer.RemoteEndPoint+"已經中斷連接"+"\r\n"); //提示套接字監聽異常 
                    listBoxOnlineList.Items.Remove(socketServer.RemoteEndPoint.ToString());//從listbox中移除斷開連接的客戶端
                    socketServer.Close();//關閉之前accept出來的和客戶端進行通信的套接字
                    break;   
                }
            }   

        
        }


        ///    
        /// 獲取當前系統時間的方法   
        ///    
        /// 當前時間   
        private DateTime GetCurrentTime()   
        {   
            DateTime currentTime = new DateTime();   
            currentTime = DateTime.Now;   
            return currentTime;   
        }


        //發送信息到客戶端 
        private void button2_Click(object sender, EventArgs e)
        {
            string sendMsg = textBox4.Text.Trim();  //要發送的信息
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg);   //將要發送的信息轉化為字節數組,因為Socket發送數據時是以字節的形式發送的

            if (listBoxOnlineList.SelectedIndex == -1)
            {
                MessageBox.Show("請選擇要發送的客戶端!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Stop);
            }
            else
            {
                string selectClient = listBoxOnlineList.Text;  //選擇要發送的客戶端
                dic[selectClient].Send(bytes);   //發送數據
                textBox4.Clear();
                textBox3.AppendText(label4.Text + GetCurrentTime() + "\r\n" + sendMsg + "\r\n");   

            }

        
           
        }

       
      

        //快捷鍵 Enter 發送信息 
       private void textBox4_KeyDown(object sender, KeyEventArgs e)
        {
            //如果用戶按下了Enter鍵   
            if (e.KeyCode == Keys.Enter)
            {
                string sendMsg = textBox4.Text.Trim();  //要發送的信息
                byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg); 
                if (listBoxOnlineList.SelectedIndex == -1)
                {
                    MessageBox.Show("請選擇要發送的客戶端!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                }
                else
                {

                    string selectClient = listBoxOnlineList.Text;  //選擇要發送的客戶端
                    dic[selectClient].Send(bytes);   //發送數據
                    textBox4.Clear();
                    textBox3.AppendText(label4.Text + GetCurrentTime() + "\r\n" + sendMsg + "\r\n");

                }
            }
        }


        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogResult result = MessageBox.Show("是否退出?選否,最小化到托盤", "操作提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                this.Dispose();
            }
            else if (result == DialogResult.Cancel)
            {
                e.Cancel = true;

            }
            else
            {
                e.Cancel = true;
                this.WindowState = FormWindowState.Minimized;
                this.Visible = false;
                this.notifyIcon1.Visible = true;
                this.ShowInTaskbar = false;
            }
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            base.Visible = true;
            this.notifyIcon1.Visible = false;
            this.ShowInTaskbar = true;
            //base.Show();
            base.WindowState = FormWindowState.Normal;
        } 
    }
}

 

 以下是客戶端的代碼:

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.Threading;
using System.Net.Sockets;
using System.Net;


namespace chat2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            StartPosition = FormStartPosition.CenterScreen;
            //關閉對文本框的非法線程操作檢查
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        //創建 1個客戶端套接字 和1個負責監聽服務端請求的線程
        Thread threadclient = null;
        Socket socketclient = null;
        List<IPEndPoint> mlist =new List<IPEndPoint>();
        private void button1_Click(object sender, EventArgs e)
        {
            //SocketException exception;
            this.button1.Enabled = false;
            //定義一個套接字監聽
            socketclient = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

            //獲取文本框中的IP地址
            IPAddress address = IPAddress.Parse(textBox1.Text.Trim());

            //將獲取的IP地址和端口號綁定在網絡節點上
            IPEndPoint point = new IPEndPoint(address,int.Parse(textBox2.Text.Trim()));

            try
            {
                //客戶端套接字連接到網絡節點上,用的是Connect
                socketclient.Connect(point);
            }
            catch (Exception )
            {
                //MessageBox.
                MessageBox.Show("連接失敗\r\n");
                this.button1.Enabled = true;
                return;
            }
            
            threadclient=new Thread(recv);

            threadclient.IsBackground=true;

            threadclient.Start();
        }

        
        
        // 接收服務端發來信息的方法  
        private void recv()//
        {
            int x = 0;
            while (true)//持續監聽服務端發來的消息
            {
                try
                {
                    //定義一個1M的內存緩沖區,用於臨時性存儲接收到的消息
                    byte[] arrRecvmsg = new byte[1024 * 1024];

                    //將客戶端套接字接收到的數據存入內存緩沖區,並獲取長度
                    int length = socketclient.Receive(arrRecvmsg);

                    //將套接字獲取到的字符數組轉換為人可以看懂的字符串
                    string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);
                    if (x == 1)
                    {
                        textBox3.AppendText("服務器:" + GetCurrentTime() + "\r\n" + strRevMsg + "\r\n\n");

                    }
                    else
                    {

                        textBox3.AppendText(strRevMsg + "\r\n\n");
                        x = 1;
                    }
                }
                catch(Exception ex)
                {
                    textBox3.AppendText("遠程服務器已經中斷連接"+"\r\n");
                    this.button1.Enabled = true;
                    break;
                }
            }
        }

        //獲取當前系統時間
        private DateTime GetCurrentTime()
        {
            DateTime currentTime = new DateTime();
            currentTime = DateTime.Now;
            return currentTime; 
        }

        //發送字符信息到服務端的方法
        private void ClientSendMsg(string sendMsg)
        {
            //將輸入的內容字符串轉換為機器可以識別的字節數組   
            byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(sendMsg);   
            //調用客戶端套接字發送字節數組   
            socketclient.Send(arrClientSendMsg);   
            //將發送的信息追加到聊天內容文本框中   
            textBox3.AppendText(this.label4.Text+": " + GetCurrentTime() + "\r\n" + sendMsg + "\r\n\n"); 
        }



        //點擊按鈕button2 向服務端發送信息 
        private void button2_Click(object sender, EventArgs e)
        {
            //調用ClientSendMsg方法 將文本框中輸入的信息發送給服務端   
            ClientSendMsg(textBox4.Text.Trim());
            textBox4.Clear();
        }

        
       
        private void textBox4_KeyDown_1(object sender, KeyEventArgs e)
        {
            //當光標位於文本框時 如果用戶按下了鍵盤上的Enter鍵
            if (e.KeyCode == Keys.Enter)
            {
                //則調用客戶端向服務端發送信息的方法  
                ClientSendMsg(textBox4.Text.Trim());
                textBox4.Clear();

            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            DialogResult result = MessageBox.Show("是否退出?選否,最小化到托盤", "操作提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                this.Dispose();
            }
            else if (result == DialogResult.Cancel)
            {
                e.Cancel = true;
                
            }
            else
            {
                e.Cancel = true;
                this.WindowState = FormWindowState.Minimized;
                this.Visible = false;
                this.notifyIcon1.Visible = true;
                this.ShowInTaskbar = false;
            }
        }



        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            base.Visible = true;
            this.notifyIcon1.Visible = false;
            this.ShowInTaskbar = true;
            //base.Show();
            base.WindowState = FormWindowState.Normal;
        }
    }
}

 

 

程序還有不足,后期還會繼續改進

客戶端在斷開連接后,應該把socket關閉;

if (result == DialogResult.Yes)

 {
           if (socketclient == null)
            {
                    this.Dispose();
            }
            else
            {
                socketclient.Close();
                this.Dispose();
             }

                      }

其他錯誤,歡迎大家指出,需要完善的地方,也希望大家給出建議


免責聲明!

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



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