使用Socket模拟聊天室

前言

Socket 是对 TCP/IP 协议的封装,Socket 只是个接口不是协议,通过 Socket 我们才能使用 TCP/IP 协议,除了 TCP,也可以使用 UDP 协议来传递数据。

 本文不对TCP/IP进行深入理解阐释,仅仅针对WinForm中如何使用Socket的几个关键点进行阐述。

 

Server

采用的是C/S架构,在某一时刻,服务器只能与一个客户端建立连接。

1、初始化,将本地IP作为Server的IP地址,端口号可以随意指定。

  public ServerForm()
        {
            InitializeComponent();
            IPAddress[] localIP = Dns.GetHostAddresses(Dns.GetHostName());      //Get any IP
            foreach (IPAddress address in localIP)
            {
                if (address.AddressFamily == AddressFamily.InterNetwork)
                {
                    tb_IPAdress.Text = address.ToString();
                }
            }
        }

2、创建监听实例,启动Server

private void StartServer_button_Click(object sender, EventArgs e)
        {
            new System.Threading.Thread(s =>
            {
                try
                {
                    TcpListener listener = new TcpListener(IPAddress.Any, int.Parse(textBox5.Text));
                    listener.Start();
                    client = listener.AcceptTcpClient();
                    strRead = new StreamReader(client.GetStream());
                    strWrite = new StreamWriter(client.GetStream());
                    strWrite.AutoFlush = true;

                    Listen_backgroundWorker.RunWorkerAsync();                         //Start recieving data 
                    Listen_backgroundWorker.WorkerSupportsCancellation = true;  
                }
                catch (Exception x)
                {
                    MessageBox.Show(x.Message.ToString());
                }
            })
            { IsBackground = true }.Start();
        }

如代码所示,新建了一个线程——线程启动了一个指定IP地址和端口号的服务端,并开始监听读写请求。如下的Listen_backgroundWorker线程,则对接收到的消息在UI上进行显示:

 private void Listen_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (client.Connected)
            {
                try
                {
                    recieve = strRead.ReadLine();
                    this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("C发送 : " + recieve + "\n"); }));
                }
                catch (Exception x)
                {
                    MessageBox.Show(x.Message.ToString());
                }
            }
        }

3、Server向已与之建立连接的Client发送消息:

 private void Send_button_Click(object sender, EventArgs e)
        {
            if (SendtextBox.Text != "")
            {
                textToSend = SendtextBox.Text;
                Send_backgroundWorker.RunWorkerAsync();
            }
            SendtextBox.Text = "";
        }

private void Send_backgroundWorker_DoWork(object sender, DoWorkEventArgs e) { if (client.Connected) { strWrite.WriteLine(textToSend); this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("S发送 : " + textToSend + "\n"); })); } else { MessageBox.Show("Send Failed!"); } Send_backgroundWorker.CancelAsync(); }

 

Client

1、将Client连接至指定IP地址和端口号Server。

        private void ConnectToServer_button_Click(object sender, EventArgs e)
        {           
            try
            {
                client = new TcpClient();
                IPEndPoint ip_End = new IPEndPoint(IPAddress.Parse(textBox6.Text), int.Parse(textBox4.Text));
                client.Connect(ip_End);
                if (client.Connected)
                {
                    Receive_textBox.AppendText("Connected to server" + "\n");
                    stw = new StreamWriter(client.GetStream());
                    str = new StreamReader(client.GetStream());
                    stw.AutoFlush = true;      
                    Receive_backgroundWorker.RunWorkerAsync();
                }
            }
            catch (Exception x)
            {
                MessageBox.Show(x.Message.ToString());
            }
        }

如下代码,在Client连接的到Server之后,也开始可以随时接收由Server传来的消息:

        private void Receive_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            while (client.Connected)
            {
                try
                {
                    recieve = str.ReadLine();
                    this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("S发送 : " + recieve + "\n"); }));
                }
                catch (Exception x)
                {
                    MessageBox.Show(x.Message.ToString());
                }
            }
        }

2、与Server建立连接的Client可以随时发送消息:

  private void Send_button_Click(object sender, EventArgs e)
        {
            if (Send_textBox.Text != "")
            {
                textToSend = Send_textBox.Text;
                Send_backgroundWorker.RunWorkerAsync();
            }
            Send_textBox.Text = "";
        }

 private void Send_backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (client.Connected)
            {
                stw.WriteLine(textToSend);
                this.Receive_textBox.Invoke(new MethodInvoker(delegate () { Receive_textBox.AppendText("C发送 :  " + textToSend + "\n"); }));
            }
            else
            {
                MessageBox.Show("Send Failed!");
            }
            Send_backgroundWorker.CancelAsync();
        }

运行结果:

 

 源码:https://github.com/Deskew/SocketChat

 

posted @ 2018-05-24 17:05  walden_yin  阅读(203)  评论(0编辑  收藏  举报