网络聊天软件项目

 

简单的网络聊天项目,实现了聊天 发文件 功能

本想打算把代码打包上传的,没找着添加附件的地方  哈哈哈.

代码如下:

------------客户端代码---------------

------------客户端代码---------------

using System;
using System.Windows.Forms;

using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;

namespace MyChatRoomClient
{
    public partial class FChatClient : Form
    {
        public FChatClient()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }
        Thread threadClient = null; //客户端负责接受服务端发来的数据消息线程
        Socket socketClient = null;

        #region 01客户端发送连接请求到服务器+void btnConnect_Click(object sender, EventArgs e)
        //客户端发送连接请求到服务器
        private void btnConnect_Click(object sender, EventArgs e)
        {
            IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
            IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //向指定的端口发送连接请求
            socketClient.Connect(endpoint);
            //创建线程 监听服务端发来的消息
            threadClient = new Thread(RecMsg);
            threadClient.IsBackground = true;
            threadClient.Start();

        }
        #endregion

        #region 02监听服务端 发来的消息+void RecMsg()
        /// <summary>
        /// 监听服务端 发来的消息
        /// </summary>
        void RecMsg()
        {
            while (true)
            {
               
                //定义一个 接受用的缓存区(2M字节数组)
                byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                //将接受到的数据 存入arrMsgRec数组 并返回真正接收到的数据的长度
                int length = socketClient.Receive(arrMsgRec);
                //此时是将 数组 所有的元素 都转成字符串, 而真正接受到的 只有服务端发来的几个字符
                string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length);
                ShowMsg(strMsgRec);
            }
        }
        #endregion

        #region 03显示消息+void ShowMsg(string msg)
        void ShowMsg(string msg)
        {
            txtMsg.AppendText(msg + " ");
        }
       
        #endregion

        #region 04发送消息到服务器+private void btnSend_Click(object sender, EventArgs e)
        //发送消息到服务器
        private void btnSend_Click(object sender, EventArgs e)
        {
            string strMsg = txtMsgSend.Text.Trim();
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
            byte[] arrMsgSend = new byte[arrMsg.Length + 1];
            arrMsgSend[0] = 0; //设置标示符 0 表示文字 文本数据.
            Buffer.BlockCopy(arrMsg, 0, arrMsgSend, 1, arrMsg.Length);

            socketClient.Send(arrMsgSend);
            ShowMsg("我说:" + strMsg);
        }
        #endregion


        #region 05选择要发送的文件+void btnChooseFile_Click
        //选择要发送的文件
        private void btnChooseFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                txtFilePath.Text = ofd.FileName;
            }
        }
         #endregion

        //06向服务端发送文件
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            //用文件流打开 用户选择的文件
            using (FileStream fs = new FileStream(txtFilePath.Text,FileMode.Open))
            {
                //定义一个2M的数组,缓存区
                byte[] arrFile = new byte[1024 * 1024 * 2];
                //将文件数据读到arrFile数组中, 并获得读取的真实数据长度length
                int length =  fs.Read(arrFile, 0, arrFile.Length);

                byte[] arrFileSend = new byte[length+1];
                arrFileSend[0] = 1;//代表发送的文件数据
                //for (int i = 0; i < length; i++)
                //{
                //    arrFileSend[i + 1] = arrFile[i];
                //}
                //将arrFile数组里的元素从第0个开始拷贝,拷贝到arrFileSend数组里,从第1个位置开始存放,以供拷贝length个数据
                Buffer.BlockCopy(arrFile, 0, arrFileSend, 1,length);
                //发送包含了标识位 的新数据数组 到服务端
                socketClient.Send(arrFileSend);
               // arrFile.CopyTo(arrFileSend, length);

            }
        }

    }
}

-------------------服务端代码------------------------------

-------------------服务端代码------------------------------

using System;
using System.Windows.Forms;


using System.Net; //IPAdress,IPEndPoint(ip和端口)类
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;
using System.IO;


namespace MyChatRoomServer
{
    public partial class FChatServer : Form
    {
        public FChatServer()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }

        Thread threadWatch = null;//负责监听 客户端 连接请求的线程
        Socket socketWatch = null; // 负责监听的套接字

        #region 01服务器启动监听的方法+void btnBeginLisen_Click(object sender, EventArgs e)
        private void btnBeginLisen_Click(object sender, EventArgs e)
        {
           
            //创建 服务端 负责监听的套接字,参数(使用IP4寻址协议,使用流式连接,使用TCP协议传输数据)
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //获得文本框中ip地址对象
            IPAddress address = IPAddress.Parse(txtIP.Text.Trim());
            //创建 包含IP 和 端口的 网络节点对象
            IPEndPoint endpoint = new IPEndPoint(address, int.Parse(txtPort.Text.Trim()));

            //将负责监听的套接字绑定到唯一的IP 和端口上
            socketWatch.Bind(endpoint);
            //设置监听队列的长度
            socketWatch.Listen(10);
            //创建负责监听的线程,并传入监听方法
            threadWatch = new Thread(WatchConnection);
            threadWatch.IsBackground = true;
           
            threadWatch.Start();
            ShowMsg("服务器启动监听成功");
          
        }
        #endregion
        //保存了服务器段 所有负责和客户端通信的套接字
        Dictionary<string, Socket> dict = new Dictionary<string, Socket>();
        //保存了服务器端, 所有负责调用 通信套接字.receive方法的线程
        Dictionary<string, Thread> dictThread = new Dictionary<string, Thread>();


        #region 02监听客户端请求的方法+void WatchConnection()
        /// <summary>
        /// 监听客户端请求的方法
        /// </summary>
        void WatchConnection()
        {
            while (true) // 持续不断的监听新的客户端的连接请求
            {
                //开始监听 客户端 连接请求 注意:Accept方法,会阻断当前的线程
                Socket sokConnection = socketWatch.Accept();// 一旦监听到客户端的请求,就返回一个负责和该客户端通信的套接字
                //向列表控件中 添加一个客户端的IP端口字符串 作为客户端的唯一标识
                lbOnline.Items.Add(sokConnection.RemoteEndPoint.ToString());
                //将与客户端通信的 套接字对象sokConnection 添加到键值对集合中 并以客户端IP端口作为键
                dict.Add(sokConnection.RemoteEndPoint.ToString(), sokConnection);
              
                //创建通信线程
                Thread thr = new Thread(RecMsg);
                thr.SetApartmentState(ApartmentState.STA);
                thr.IsBackground = true;
                //启动先换成 并为线程要调用的方法RecMsg 传入参数sokConnection
                thr.Start(sokConnection);
                //将线程 保存在 字典里,方便大家以后做"踢人"功能
                dictThread.Add(sokConnection.RemoteEndPoint.ToString(), thr);

                ShowMsg("客户端连接成功!" + sokConnection.RemoteEndPoint.ToString());
            }
        }
        #endregion

        #region 03服务端 负责监听 客户端 发来的数据的方法+void RecMsg(object socketClientPara)
        /// <summary>
        /// 服务端 负责监听 客户端 发来的数据的方法
        /// </summary>
        void RecMsg(object socketClientPara)
        {
            Socket socketClient = socketClientPara as Socket;
           
            while (true)
            {
                byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                int length = -1;
                try
                {
                    length = socketClient.Receive(arrMsgRec);
                }
                catch (SocketException ex)
                {
                    ShowMsg("异常:" + ex.Message);
                    //从 通信套接字集合中删除被中断连接的 通信套接字对象
                    dict.Remove(socketClient.RemoteEndPoint.ToString());
                    //从 通信线程 集合中删除被终端连接的通信线程独享
                    dictThread.Remove(socketClient.RemoteEndPoint.ToString());
                    //从列表中移除 被中断的连接 ip :port
                    lbOnline.Items.Remove(socketClient.RemoteEndPoint.ToString());
                    break;
                }
                catch (Exception ex)
                {
                    ShowMsg("异常:" + ex.Message);
                    break;
                }
                if (arrMsgRec[0]==0)//判断发送过来的数据的第一个元素 是0 代表文本文字数据
                {
                    string strMsgRec = System.Text.Encoding.UTF8.GetString(arrMsgRec, 1, length-1);
                    ShowMsg(strMsgRec);
                }
                else if (arrMsgRec[0]==1)//如果是1 代表发送过来的是 文件数据(图片/视频/等等..)
                {
                    //保存文件选择框对象
                    SaveFileDialog sfd = new SaveFileDialog();
                    if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)//用户选择文件路径后
                    {
                        string fileSavePath = sfd.FileName; //获得要保存的文件路径
                        //创建文件流,然后让文件流根据路径创建一个文件
                        using (FileStream fs = new FileStream(fileSavePath, FileMode.Create))
                        {
                            fs.Write(arrMsgRec, 1, length - 1);
                            ShowMsg("文件保存成功"+ fileSavePath);
                        }
                      
                    }

                }
               
            }
        }
        #endregion

        #region 04显示消息+ void ShowMsg(string msg)
        void ShowMsg(string msg)
        {
            txtMessage.AppendText(msg + " ");
        }
        #endregion

        #region 05发送消息到客户端+void btnSend_Click(object sender, EventArgs e)
        //发送消息到客户端
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(lbOnline.Text))
            {
                MessageBox.Show("请选择发送的好友!");
            }
            else
            {
                string strMsg = txtMsgSend.Text.Trim();
                //将要发送的字符串 转成utf8对应的字节数组
                byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
                //获得列表中选中的key
                string strClientKey = lbOnline.Text;
                //通过key,找到字典集合 中对应的和某个客户端通信的套接字的 send方法,发送数据给对方
                try
                {
                    dict[strClientKey].Send(arrMsg);
                    //sokConnection.Send(arrMsg);
                    ShowMsg("发送了数据: " + strMsg);
                    txtMsgSend.Text = string.Empty;
                }
                catch (SocketException ex)
                {
                    ShowMsg("发送时异常:" + ex.Message);
                  
                }
                catch (Exception ex)
                {
                    ShowMsg("发送时异常:" + ex.Message);
                }
              
            }
        }
        #endregion

        #region 06服务端群发消息+void btnSendToAll_Click(object sender, EventArgs e)
        //服务端群发消息
        private void btnSendToAll_Click(object sender, EventArgs e)
        {
            string strMsg = txtMsgSend.Text.Trim();
            //将要发送的字符串 转成utf8对应的字节数组
            byte[] arrMsg = System.Text.Encoding.UTF8.GetBytes(strMsg);
            foreach (Socket s in dict.Values)
            {
                s.Send(arrMsg);
            }
            ShowMsg("群发完毕 : )");

        }
        #endregion

       
    }
}


 

原文地址:https://www.cnblogs.com/chenanzixue/p/3465260.html