黑马程序员-多线程聊天室

来源:互联网 发布:天天模拟器mac版 编辑:程序博客网 时间:2024/05/16 16:56

---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------------------


服务端界面


代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Threading;
using System.IO;


namespace myserver
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;//打开微软对TextBox的 跨线程 操作
        }
        Socket socketWatch = null;//创建一个套接字
        Thread threadWatch = null;//创建一个监听线程
        //创建一个监听多个客户端的 套接字 字典
        Dictionary<string, Thread> dictthread = new Dictionary<string, Thread>();       
        


        private void btsart_Click(object sender, EventArgs e)
        {
            //创建一个负责监听的套接字 参数(使用IPV4寻址方式   ,  使用流式连接  ,   使用TCP协议传输数据)
            socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //取得一个IPAddress的类型的ip地址
            IPAddress ip = IPAddress.Parse(txtip.Text.Trim());
            //取得ip地址和端口
            IPEndPoint point = new IPEndPoint(ip, int.Parse(txtport.Text.Trim()));
            //连接要监听套接字绑定到唯一的IP和端口.
            socketWatch.Bind(point);
            //设置队列长度
            socketWatch.Listen(10);
            //开始监听 客户端的 连接 请求
            //Socket xin = socketWatch.Accept();//Accept会阴断当前线程
            Mymsc("监听成功");
            //创建一个线程 监听客户端新的请求
            threadWatch = new Thread(Connting);
            //设为后台线程
            threadWatch.IsBackground = true;
            //开始线程
            threadWatch.Start();
            //防止第二次服务连接
            btsart.Text="服务启动";
            btsart.Enabled = false;
        }
        /// <summary>
        /// 监听客户端的请求,存入字典,做为向哪个客户端进行通信的标识.
        /// </summary>
        Dictionary<string,Socket> dict=new Dictionary<string,Socket>();
        void Connting()
        {
            while (true)//不断的 监听 新的连接 请求
            {
                //开始监听 客户端的 连接 请求 Accept会阴断当前线程
                Socket xin = socketWatch.Accept();//一旦监听到请求,就会创建一个 xin 套接字 来进行通信 
                //向列表控中 添加 套接字客户端 的ip 和 端口,作为客户端的标识
                listBox1.Items.Add(xin.RemoteEndPoint.ToString());
                //将与客户端通信的 套接字对象 xin 添加到 键盘值和集合中,并以客户端ip端口为主键                
                dict.Add(xin.RemoteEndPoint.ToString(), xin);
                //创建线程委托
                ParameterizedThreadStart slp=new ParameterizedThreadStart(Msgwatch);
                //为新创建的套接字 建立一个线程 执行监听来自客户端的数据                
                Thread jsMsg = new Thread(slp);
                //设置为后台线程
                jsMsg.IsBackground = true;
                //开始运行线程 并传入新建立的套接字win的参数
                jsMsg.Start(xin);
                //把线程加入到dictthread的字典
                dictthread.Add(xin.RemoteEndPoint.ToString(), jsMsg);
                Mymsc("客户端连接成功" + xin.RemoteEndPoint.ToString());
                //msgWatch = new Thread(Msgwatch);
                //msgWatch.IsBackground = true;
                //msgWatch.Start();
            }
        }
        /// <summary>
        /// 监听来自客户端传来的数据
        /// </summary>
        /// <param name="socket"></param>
        void Msgwatch(object socket)
        {
            //不停的监听
            while (true)
            {
                //把获取的参数转换为Socket类型
                Socket socketWatch = socket as Socket;
                //定个一个1M的字节数组 用来接收来自客户端的数据
                byte[] jieshou = new byte[1024 * 1024 * 2];
                
                int length = 1;
                try
                {
                    //得到传过来字节的长度 jieshou得到传来的数据
                     length = socketWatch.Receive(jieshou);
                   
                }
                catch (SocketException )//判断是否有Socket的异常发生
                {
                    //删除字典内关闭了的用户
                    dict.Remove(socketWatch.RemoteEndPoint.ToString());
                    //删除了线程 
                    dictthread.Remove(socketWatch.RemoteEndPoint.ToString());
                    //删除被关闭的用户 
                    listBox1.Items.Remove(socketWatch.RemoteEndPoint.ToString());
                    Mymsc(socketWatch.RemoteEndPoint.ToString() + "断开了连接");
                    break;
                    
                }
                if (jieshou[0] == 0)
                {
                    //把传来的字节数据转换为字符串
                    string str = System.Text.Encoding.UTF8.GetString(jieshou, 1, length - 1);
                    //显示得到的数据
                    Mymsc("接收到" + socketWatch.RemoteEndPoint.ToString() + "数据:" + str);
                }
                else if (jieshou[0] == 1)
                {
                    SaveFileDialog savefile = new SaveFileDialog();
                    if (savefile.ShowDialog() == DialogResult.OK)
                    {
                        using (FileStream fs = new FileStream(savefile.FileName, FileMode.CreateNew))
                        {
                            fs.Write(jieshou, 1, length - 1); 
                            
                        }


                    }
                    Mymsc("保存成功" + savefile.FileName);


                }
            }
          
        }
        /// <summary>
        /// 向文本框中输出数据
        /// </summary>
        /// <param name="msc"></param>
        void Mymsc(string msc)
        {
            textBox1.AppendText(msc + "\r\n");
        }


        private void 发送数据_Click(object sender, EventArgs e)
        {
            //得到要发送的数据
            string str = txtmsg.Text.Trim();
            //把需要发送的数据转换成UTF8的字节
            byte[] byt=System.Text.Encoding.UTF8.GetBytes(str);
            if (string.IsNullOrEmpty(listBox1.Text))
            {
                MessageBox.Show("请选择要发送的好友");
            }
            else
            {
                //获取选中的客户端ip和端口
                string stryh = listBox1.Text;
                //向xin套接字发送数据
                dict[stryh].Send(byt);
                //显示发出的数据
                Mymsc("发出去的数据" + str);
            }
            //表空txtmsg文本内的数据
            txtmsg.Clear();
            //获得焦点
            txtmsg.Focus();


        }




        private void button1_Click(object sender, EventArgs e)
        {
            //得到要发送的数据
            string str = txtmsg.Text.Trim();
            //把需要发送的数据转换成UTF8的字节
            byte[] byt = System.Text.Encoding.UTF8.GetBytes(str);
            foreach (Socket d in dict.Values)
            {
                d.Send(byt);
            }


        }  


       


       
    }
}

客户端界面


代码如下:

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




namespace 客户端
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            TextBox.CheckForIllegalCrossThreadCalls = false;
        }
        Thread jieshou = null;
        Socket scoketkehu = null;
       
        private void btlish_Click(object sender, EventArgs e)
        {
            //创建一个套接字  参数(指定ipv4寻址方式,使用流式连接,使用TCP数据传输)
            scoketkehu = 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()));
            //连接服务端
            scoketkehu.Connect(endpoint);
            Mymsc("连接成功");
            //建立一个线程,监听服务端传来的消息
            jieshou = new Thread(js);
            //把线程设置为后台线程
            jieshou.IsBackground = true;
            //线程开始
            jieshou.Start();
          
        }
        /// <summary>
        /// 不停监听服务端传来的消息
        /// </summary>
        void js()
        {
            while (true)
            {
                //建立一个1M的byte字节的数组
                byte[] arrMsg = new byte[1024 * 1024];
                //接收传过来的信息存到arrMsg字节数组中,并把长度赋给i
                int i=scoketkehu.Receive(arrMsg);
                //把字节数组转换成字符串
                string strMsg = System.Text.Encoding.UTF8.GetString(arrMsg,0,i);
                //输出到文本框
                Mymsc("服务端信息:"+strMsg);
            }
        }


        /// <summary>
        /// 向文本框中输出信息
        /// </summary>
        /// <param name="msc"></param>
        void Mymsc(string msc)
        {
            textBox1.AppendText(msc + "\r\n");
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //从txtmsg.txt中获取要发的消息
            string str=txtmsg.Text.Trim();
            //把要发的信息转换成UTF8文件格式的字节数组
            byte[] input = System.Text.Encoding.UTF8.GetBytes(str);
            byte[] arrmsgsend=new byte[input.Length+1];
            arrmsgsend[0] = 0;
            Buffer.BlockCopy(input, 0, arrmsgsend, 1, input.Length);
            //向客户端发送消息
            scoketkehu.Send(arrmsgsend);
            //转出发出的信息
            Mymsc("发出的消息" + str);


        }
        /// <summary>
        /// 得到文件路径
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btselectfile_Click(object sender, EventArgs e)
        {
            //显示一个打开始文件的对话框
            OpenFileDialog ofd = new OpenFileDialog();
            //判断是否有打开文件
            if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtfilepath.Text=ofd.FileName;//把得到的文件路径传给text控件;
               
            }
        }
        //向服务端发送文件
        private void btsendfile_Click(object sender, EventArgs e)
        {
            //打开要发送的文件
            using (FileStream file = new FileStream(txtfilepath.Text.Trim(), FileMode.Open))
            {
                //定义一个2M的缓存空间
                byte[] byt = new byte[1024 * 1024 * 2];
                //读取文件存到byt字节数组,获取所读文件长度
                int length=file.Read(byt, 0, byt.Length);
                //定一个可以有标识符的字节数组
                byte[] arrfile = new byte[length+1];
                //给标识符赋值
                arrfile[0] = 1;
                //复制byt数组的数据(从第0个字符开始复制),到arrfile数级内(从第1个开始写入)
                Buffer.BlockCopy(byt, 0, arrfile, 1, length);
                //向服务端传送数据
                scoketkehu.Send(arrfile);
                Mymsc("文件发送成功");
            }
        }


       
        
    }
}



---------------------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------------------