这两天在网上看了些视频,写了一个简单的聊天室的功能:想把它分享出来!以至于忘记!希望大家看过以后 提哈意见!

窗口设计样式如图:

 服务端:

   就是说哈如何获得IP地址了,我用的方法就是在运行里---cmd--ipconfig来获得ip地址,我当时乱写的IP地址根本不行:所以写这种方法,希望这个方法能帮助在这里遇到同样的问题的朋友们!虽然我是一个菜鸟!但是我想程序写的明了!

 

    下面就是关于引用:这里因为要用到多线程、用到套节字、操作文件所以引用相应的类!

下面为客户端的代码:

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

namespace QQ1
{
    public partial class Clinet : Form
    {
        public Clinet()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }
        Socket requestCon = null;
        #region 建立连接
        private void btnSendCon_Click(object sender, EventArgs e)
        {
            IPAddress IP = IPAddress.Parse(txtIP.Text.ToString().Trim());
            IPEndPoint endPoint = new IPEndPoint(IP, int.Parse(txtPort.Text.ToString()));
            requestCon = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            requestCon.Connect(endPoint);
            Thread threadReceive = new Thread(ReceiveMsg);
            threadReceive.IsBackground = true;
            threadReceive.Start();
        }
        #endregion

        #region 显示所有的消息(发送和收到的)
        public void ShowAllMsg(string Msg)
        {
            txtShowAllMsg.AppendText(Msg + "\n");
        }

        #endregion

        #region 发送信息
        private void btnSend_Click(object sender, EventArgs e)
        {
            string sendMsg = txtSendMsg.Text.ToString().Trim();
            byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendMsg);
            byte[] arrsengMsgAgain = new byte[arrSendMsg.Length + 1];       
            Buffer.BlockCopy(arrSendMsg, 0, arrsengMsgAgain, 1, arrSendMsg.Length);
            arrsengMsgAgain[0] =0;
            try
            {
                requestCon.Send(arrsengMsgAgain);
                ShowAllMsg("你说:" + sendMsg);
            }
            catch (SocketException ex)
            {

                MessageBox.Show("接收消息发生异常" + ex.Message);//每次调用Socket对象的方法的时候 ,一定捕捉异常
            }
            catch(Exception ex)
            {
                MessageBox.Show("接收消息发生异常" + ex.Message);
            }
        }
        #endregion

        #region  收到消息
        public void ReceiveMsg()
        {                                           
            while (true)
            {
                byte[] arrRecevieMsg = new byte[1024 * 1024 * 2]

                try
                {

                     nt length = requestCon.Receive(arrRecevieMsg);//因为这里接收它一直在接收,它会阻塞线程,所以我们一定要在这里使用线程(对这个方法)!
                    string RecevieMsg = Encoding.UTF8.GetString(arrRecevieMsg, 0, length);//因为这里发关
                    ShowAllMsg("他说:" + RecevieMsg);
                }
                catch (SocketException ex)
                {

                    MessageBox.Show("接收消息发生异常!" + ex.Message);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("接收消息发生异常!" + ex.Message);//所有与网络通信的地方都要获得异常!
                }
            }
        }
        #endregion

        #region 得到路径
        private void btnFindFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                txtFilePath.Text = ofd.FileName;
            }
        }

        #endregion

        #region 发送文件
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            using (FileStream fs = new FileStream(txtFilePath.Text, FileMode.Open))
            {
                byte[] arrFile = new byte[1024 * 1024 * 2];//先得到一个你想要的空间,我们这里定义的2M
                int length = fs.Read(arrFile, 0, arrFile.Length);//然后调用文件文件的Read方法,把它读到这里文件里面去,从0开始,到我们定义的文件长度arrFile.Length,但是这里它有一个返回值 ,这个文件真实文件长度length!
                byte[] arrSendFile = new byte[length + 1];//然后我们再声明一个新的字节数组,它的长度,就是比它的真实长度加1;
                arrSendFile[0] = 1;//我们给它的字节数组的开头1,说明我想传的是文件

                Buffer.BlockCopy(arrFile,0,arrSendFile,1,length);//这里就用Buffer的BlockCopy方法,它的参数第一个:原来文件!,第二参数:从什么位置开始,第三个参数:复制那个新字节数组中,第四个参数:旧文件在新文件那个位置开始复制,因为我们前面已经定义新字节数组第一个参数为0,所以我们这里要从1开始:第五参数: 这个个复制的数据有多长!

           requestCon.Send(arrSendFile);//开始发送文件!
            }
        }
        #endregion
    }
}

下面是服务器端的代码:

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

namespace QQ
{
    public partial class txtState : Form
    {
        public txtState()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }
        Socket socketWatch = null;
        Dictionary<string, Thread> thread = new Dictionary<string, Thread>();
        Dictionary<string, Socket> socket = new Dictionary<string, Socket>();

        private void btnConnect_Click(object sender, EventArgs e)
        {
            IPAddress ipAddress = IPAddress.Parse(txtIP.Text.ToString().Trim());
            IPEndPoint endPoint = new IPEndPoint(ipAddress, int.Parse(txtPort.Text.Trim()));
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketWatch.Bind(endPoint);
            socketWatch.Listen(10);
            ShowMsg("开始连接");
            //socketWatch.Accept();//因为这个方法调用要阻滞程序,所以把它写在线程里面去


            Thread th = new Thread(WatchRequst);//我们对监听使用线程!
            th.IsBackground = true;
            th.Start();
        }
        public void WatchRequst()
        {
            while (true)
            {
                Socket socketStart = socketWatch.Accept();//每次监听到请求,这里会创建一个SOCKET对象!,我们拿到它的那个那个IP地址发送的数据:这里使用这用socketStart.RemoteEndPoint.ToString(),拿到远程IP和Port
                Thread threadReceive = new Thread(ReceiveMsg);//这样产生每个线程的时候,绑定ReceiveMsg方法
                threadReceive.IsBackground = true;
                threadReceive.Start(socketStart);//这里给方法传了一个SOCKET对象!每次调用的时候都是一个新的SOCKET对象
                listOnLine.Items.Add(socketStart.RemoteEndPoint.ToString());//添加到列表框中
                socket.Add(socketStart.RemoteEndPoint.ToString(), socketStart);//添加到字典中的Socket对象
                thread.Add(socketStart.RemoteEndPoint.ToString(), threadReceive);  //把线程对象添加字典中!        
                ShowMsg("连接成功!");
            }
        }
        #region 添加显示到显示状态框
        public void ShowMsg(string Msg)
        {
            txtShowConState.AppendText(Msg+"\t");
        }
        #endregion

        # region 循环接收消息
        public void ReceiveMsg(object soc)
        {
            Socket socketReceive = soc as Socket;//把类型进行转化
            while (true)
            {
                byte[] arrReceive = new byte[1024 * 1024 * 2];//只设置了它的大小 没有放身体任何的东西

                int length = -1;

                try//当断开连接的时候会出现异常 所以这里来异常处理!
                {
                    length=socketReceive.Receive(arrReceive);//这里方法报出异常,这里捕获异常,这里是客户端的连接突然关闭的时候报的异常

                }
                catch (SocketException ex)
                {

                    ShowReceiveMsg(ex.Message);
                    socket.Remove(socketReceive.RemoteEndPoint.ToString());//当服务器的删除相应的SOCKET对象,这里虽然出现异常但是这里对象还在!所以我们能到拿 到对象的socketReceive.RemoteEndPoint;,因为我的字典的集合,都是使用远程的IP和Port作Key
                    thread.Remove(socketReceive.RemoteEndPoint.ToString());//删除Socket对应的线程
                   //从列表移除远程端口
                    listOnLine.Items.Remove(socketReceive.RemoteEndPoint.ToString());//删除列表存在的IP和port
                    return;
                }
                catch(Exception ex)
                {
                    ShowReceiveMsg(ex.Message);
                    return;
                }

                if (arrReceive[0]==0)                                                                   
                {
                    string Msg = Encoding.UTF8.GetString(arrReceive, 1, length-1);
                    ShowReceiveMsg("他说:" + Msg);
                }
                else if (arrReceive[0] == 1)
                {
                    SaveFileDialog sfd = new SaveFileDialog();
                    if (sfd.ShowDialog() == DialogResult.OK)
                    {
                        string filePath = sfd.FileName;
                        using (FileStream fs = new FileStream(filePath, FileMode.Create))
                        {
                            fs.Write(arrReceive, 1, length-1);
                            ShowReceiveMsg("接收成功!");
                        }
                    }
                }
               
            }
        }
        #endregion

        # region  显示消息的方法

        public void ShowReceiveMsg(string msg)
        {
            txtShowMsg.AppendText(msg+"\n");
        }
        #endregion

        #region 发送信息
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(listOnLine.Text))
            {
                MessageBox.Show("请选择发送的客户");
            }
            else
            {
                string Msg = txtSendMsg.Text.Trim().ToString();
                byte[] arrSendMsg = Encoding.UTF8.GetBytes(Msg);
                try
                {

                    socket[listOnLine.Text].Send(arrSendMsg);
                    ShowReceiveMsg("你说:" + Msg);
                }
                catch (SocketException ex)
                {

                    MessageBox.Show("发送时出现异常!" + ex.Message);//只要是socket对象跟网络连接都要来获得异常
                }
                catch (Exception ex)
                {
                    MessageBox.Show("发送时出现异常!" + ex.Message);
                }
            }
        }
        #endregion

        #region 找到文件所在的路径 并把它的路径给显示到文本框(txtFilePath)
        private void btnFindFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog opd = new OpenFileDialog();
            if (opd.ShowDialog()==DialogResult.OK)
            {
                txtFilePath.Text = opd.FileName.ToString();
            }
        }
        #endregion
      
    }
}

 

 

posted on 2011-11-03 22:12  mmdlp3  阅读(291)  评论(0编辑  收藏  举报