c#多人聊天室

来源:互联网 发布:科学网 博弈 复杂网络 编辑:程序博客网 时间:2024/06/06 02:46

用c#写的一个多人聊天室的小程序 用的是socket  没用TcpClien以下是代码

客户端:

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;using System.Threading;using System.Net.Sockets;namespace 客户端{    public partial class Form1 : Form    {        Socket lian;        public Form1()        {             InitializeComponent();        }        /// <summary>        /// 不停接收信息的线程        /// </summary>        void jieshou()        {            while (true)            {                Byte[] buff = new Byte[1000];                try                {                    int s = lian.Receive(buff);                    if (s == 0)                        break;                    string str = Encoding.UTF8.GetString(buff, 0, s);                    this.Invoke(new Action(() =>                    {                        this.neirong.AppendText(str + "\r\n");                    }));                }                catch { }            }        }        /// <summary>        /// 发送消息        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void button1_Click(object sender, EventArgs e)        {            if (this.button2.Text != "关闭")            {                MessageBox.Show("请先连接");                return;            }            string str = this.liaotian.Text;            string strr = this.name.Text + ":" + str;            byte[] buf = Encoding.UTF8.GetBytes(strr);            try            {                lian.Send(buf);            }            catch            {                //服务器关闭 或者发生异常 断开连接                lian.Close();                MessageBox.Show("请重新连接");                this.button2.Text = "连接";                return;            }            this.liaotian.Clear();            this.neirong.AppendText("我:" + str + "\r\n");        }        /// <summary>        /// 点第一次连接  第二次关闭连接         /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void button2_Click(object sender, EventArgs e)        {            if (this.button2.Text == "关闭")            {                lian.Close();                this.button2.Text = "连接";                return;            }            try            {                //创建负责通信的Socket                lian = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                IPAddress ip = IPAddress.Parse("127.0.0.1");                IPEndPoint point = new IPEndPoint(ip, 3333);                //获得要连接的远程服务器应用程序的IP地址和端口号                lian.Connect(point);                //开启一个新的线程不停的接收服务端发来的消息                Thread t = new Thread(jieshou);                t.IsBackground = true;                t.Start();                this.button2.Text = "关闭";            }            catch            {             }        }    }}
服务器端:

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;namespace 聊天室{    public partial class Form1 : Form    {        //所有通信的socket        List<Socket> alllian = new List<Socket>();        /// <summary>        /// 初始化界面 同时开启服务器监听        /// </summary>        public Form1()        {            InitializeComponent();            //防止线程无法访问ui界面的控件    但是隐患太大 推荐使用this.Invoke(new Action(() =>            //Control.CheckForIllegalCrossThreadCalls = false;            try            {                //新建套接字                Socket jianting = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                // 绑定               可用ip                jianting.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3333));                //同时连接的最大上限  多了排队                jianting.Listen(2);                //创建后台线程一直等待连接连接                Thread t = new Thread(lianjie);                t.IsBackground = true;                t.Start(jianting);            }            catch { }        }        /// <summary>        /// 一直监听 线程只能传object        /// </summary>        /// <param name="jianting"></param>        void lianjie(object jianting)        {            while (true)            {                Socket jt = (Socket)jianting;                //返回通信的套接字                try                {                    Socket l = jt.Accept();                    //持续接收消息                    alllian.Add(l);                    Thread t = new Thread(jieshou);                    t.IsBackground = true;                    t.Start(l);                }                catch { }            }        }        /// <summary>        /// 持续接收发来的消息        /// </summary>        /// <param name="l"></param>        void jieshou(object ll)        {            Socket l = (Socket)ll;            while (true)            {                Byte[] buff = new Byte[1000];                try                {                    int s = l.Receive(buff);                    if (s == 0)                    {                        alllian.Remove(l);                        break;                    }                    //显示内容                    string str = Encoding.UTF8.GetString(buff, 0, s);                    this.Invoke(new Action(() =>                    {                        this.neirong.AppendText(str + "\r\n");                    }));                    buff = Encoding.UTF8.GetBytes(str);                    //发送给别人 直接用发来bytes转发的话有一些问题 长度不匹配                    foreach (Socket all in alllian)                    {                        if (all != l)                            try                            {                                all.Send(buff);                            }                            catch                            {                                continue;                            }                    }                }                catch { }            }        }        /// <summary>        /// 发送消息给所有人        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void fasong_Click(object sender, EventArgs e)        {            bool r=false;            string str =  this.liaotian.Text;            string strr = "房主:" + str;            byte[] buf = Encoding.UTF8.GetBytes(strr);            //给所有人发送消息 不要用foreach 报错 集合已修改 无法进行枚举操作            for (int i = 0; i < alllian.Count;i++ )            {                try                {                    alllian[i].Send(buf);                    r = true;                }                catch                {                    alllian.Remove(alllian[i]);                    i--;                    continue;                }            }            //如果可以发送出去消息 则还有人连接            if (r)            {                this.liaotian.Clear();                this.neirong.AppendText("我:"+str + "\r\n");            }            else            {                alllian.Clear();                MessageBox.Show("无人聊天");            }        }    }}
写完这个小程序有几点需要总结的:

1.socket、线程、集合的使用  

socket:多练练就会用了 网上资料不少

线程:传参数只能是object 之后可强转 可 as(比较安全)  winform程序线程想访问控件最好使用

this.Invoke(new Action(() => 这类的操作        

而 Control.CheckForIllegalCrossThreadCalls = false; 只是拆了东墙补

集合:在循环里进行操作勿用foreach  比如集合在删除中间元素的时候后面的元素会往前移动 for删除完元素之后 i--退一位即可 

2.通信的双方不能明确的知晓对方是否断开连接

服务器:客户端断开连接,服务器发送消息的时候会报异常

客户端:服务器关闭 ,客户端发送消息会报异常

捕捉这个异常 则证明对方断开连接  做相应的处理(这样不太正规,万一不是断开连接引起的异常就不好了) 这个我用着还可以

3.关于检测对方是否断开连接的方法

百度有不少  心跳包是主流  我的方法是偏方 - - 




原创粉丝点击