天天看点

Winfrom使用Socket双向通信 -- 聊天程序(客户端、服务端) -- 01

使用Winfrom写一个聊天软件

  • ​​效果图​​
  • ​​原理​​
  • ​​代码实现​​
  • ​​服务端​​
  • ​​客户端​​
  • ​​注意事项​​

效果图

原理

代码实现

服务端

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

namespace ScoketServerTest
{
    public partial class Server : Form
    {
        public Server()
        {
            InitializeComponent();
        }
        /// <summary>
        /// socket套接字
        /// </summary>
        Socket socketServer = null;
        /// <summary>
        /// 客户端
        /// </summary>
        Socket socketClienCon = null;
        /// <summary>
        /// 客户端信息
        /// </summary>
        string clientIpMsg = string.Empty;
        /// <summary>
        /// 服务器是否关闭  false:开启  true:已关闭
        /// </summary>
        bool isClose = false;

        private void Server_Load(object sender, EventArgs e)
        {
            // 获取当前主机名
            this.textBox1.Text = System.Net.Dns.GetHostName();
            // 默认端口设置为33333
            this.portTex.Text = "33333";
            // 根据主机名获取ip地址
            //注意获取的是IPV4的地址,有些电脑如果第一个就是IPV4可以把索引'1'更换成'0'
            this.ipTex.Text = System.Net.Dns.GetHostEntry(this.textBox1.Text).AddressList[1].ToString();
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            try
            {
                // 获取输入框的ip地址
                IPAddress ip = IPAddress.Parse(this.ipTex.Text.ToString().Trim());
                // 获取端口号
                int port = int.Parse(this.portTex.Text.ToString().Trim());
                IPEndPoint ipe = new IPEndPoint(ip,port);
                socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                // 绑定网络终结点
                socketServer.Bind(ipe);
                // 设置监听最大连接数
                socketServer.Listen(10);
                isClose = false;
                this.lstRev.Items.Add(string.Format("服务器已开启,开始监听消息"));
                this.lstRev.Items.Add(string.Format("当前主机名:{0}", this.textBox1.Text));
                this.lstRev.Items.Add(string.Format("当前IP:{0}", System.Net.Dns.GetHostEntry(this.textBox1.Text).AddressList[0].ToString()));
               
                Thread clientThread = new Thread(ListenTh);  //创建一个线程,用于监听客户端连接
                clientThread.IsBackground = true;  //设置为后台线程
                clientThread.Start();  //开启线程
                Thread revThread = new Thread(RevTh);  //创建一个线程,用于监听客户端发来的消息
                revThread.IsBackground = true;//设置为后台线程
                revThread.Start();  //开启线程

            }
            catch (Exception ex)
            {

                string errorMsg = string.Format("服务器开启失败,失败原因:{0}", ex.Message.ToString());
                this.lstRev.Items.Add(errorMsg);
            }
        }


        /// <summary>
        /// 监听客户端
        /// </summary>
        private void ListenTh()
        {
            while (!isClose)
            {
                try
                {
                    socketClienCon = socketServer.Accept();  //为监听到的客户端创建新的套接字
                    IPAddress clientIp = (socketClienCon.RemoteEndPoint as IPEndPoint).Address;  //获取连接的客户端的IP地址
                    int clientPort = (socketClienCon.RemoteEndPoint as IPEndPoint).Port;  //获取连接的客户端的端口号
                    clientIpMsg = string.Format("客户端IP:{0},端口号:{1}", clientIp, clientPort);
                    OnlineClient(clientIpMsg);  //在线用户并打印到在线用户窗口
                }
                catch (Exception ex)
                {
                    string error = string.Format("监听客户端信息异常,错误原因:{0}", ex.Message.ToString());
                    Recevice(error);
                    break;
                }
            }
        }
        delegate void OnlineClientDele(string clientMsg);  //创建在线用户委托方法
        /// <summary>
        /// 在线用户
        /// </summary>
        /// <param name="clientMsg">在线用户信息</param>
        private void OnlineClient(string clientMsg)
        {
            if (this.InvokeRequired)
            {
                OnlineClientDele oel = new OnlineClientDele(OnlineClient);
                this.Invoke(oel, new object[] { clientMsg });
            }
            else
            {
                this.lstClient.TopIndex = this.lstClient.Items.Count - 1;
                this.lstClient.Items.Add(clientMsg);
            }
        }

        /// <summary>
        /// 接收客户端消息
        /// </summary>
        private void RevTh()
        {
            while (!isClose)
            {
                if (socketClienCon != null)
                {
                    try
                    {
                        byte[] clientMsg = new byte[1024];  //创建接收消息缓存数组
                        int msgLen = socketClienCon.Receive(clientMsg);  //接收从客户端发来的数据
                        if (msgLen == 0)
                        {
                            break;
                        }
                        else
                        {
                            string msg = string.Format("{0}【收到 ← 来自:{1}】:\n{2}", DateTime.Now, clientIpMsg, Encoding.UTF8.GetString(clientMsg, 0, msgLen));
                            Recevice(msg);  //接收消息并打印到对话窗口
                        }
                    }
                    catch (Exception ex)
                    {
                        string error = string.Format("接收客户端消息异常,错误原因:{0}", ex.Message.ToString());
                        Recevice(error);
                        break;
                    }
                }
            }
        }
        delegate void ReceviceDele(string msgStr); //创建接收消息委托方法
        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="msg">客户端发来的消息</param>
        private void Recevice(string msg)
        {
            if (this.InvokeRequired)
            {
                ReceviceDele rel = new ReceviceDele(Recevice);
                this.Invoke(rel, new object[] { msg });
            }
            else
            {
                this.lstRev.TopIndex = this.lstRev.Items.Count - 1;
                this.lstRev.Items.Add(msg);
            }
        }       
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            string msg = this.txtSend.Text.ToString().Trim();
            byte[] msgByt = Encoding.UTF8.GetBytes(msg);
            socketClienCon.Send(msgByt);
            this.lstRev.Items.Add(string.Format("{0}【发送 → 至 {1}】:\n{2}", DateTime.Now, clientIpMsg, msg));
            this.txtSend.Text = "";
        }
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            isClose = true;
            socketServer.Close();
        }
        private void btnClose_Click(object sender, EventArgs e)
        {
            isClose = true;
            socketServer.Close();
        }

       
    }
}      

客户端

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

namespace WebspcketClientTest
{
    public partial class Client : Form
    {
        public Client()
        {
            InitializeComponent();
        }

        /// <summary>
        /// socket套接字
        /// </summary>
        Socket cilentSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        bool isClose = true;

        private void Client_Load(object sender, EventArgs e)
        {
            this.portTex.Text = "33333";
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            //获取ip
            IPAddress ip = null;
            if (!string.IsNullOrEmpty(this.ipTex.Text.ToString().Trim()))
            {
                ip = IPAddress.Parse(this.ipTex.Text.ToString().Trim());
            }
            else if(!string.IsNullOrEmpty(this.texHostName.Text.ToString().Trim()))
            {
                IPAddress[] addressList = Dns.GetHostEntry(this.texHostName.Text.ToString().Trim()).AddressList;
                // 根据HostName 获取IPV4地址
                string ipStr = addressList[0].ToString();
                if (ipStr.Length > 17)
                {
                    ipStr = addressList[1].ToString();
                }
                // IP地址

                ip = IPAddress.Parse(ipStr);
     
                this.ipTex.Text = ip.ToString();
            }
            else
            {
                MessageBox.Show("无法获取主机地址!");
                this.richTextBox1.Text += "无法获取主机地址!\n";
                return;
            }
             
            //获取端口号
            IPEndPoint ep = new IPEndPoint(ip, int.Parse(this.portTex.Text));
            //ws = new WebSocketSharp.WebSocket("ws://" + this.texHostName.Text + ":" + this.portTex.Text);
            try
            {
                //ws.Connect();
                //建立连接
                cilentSocket.Connect(ep);
                this.richTextBox1.Text += "连接成功!\n";
                isClose = false;
                Thread th = new Thread(StartMsg);
                th.IsBackground = true;
                th.Start();
            }
            catch (Exception ex)
            {
                this.richTextBox1.Text += string.Format("连接失败,原因{0}1\n", ex.ToString());
            }
        }

        // 监听服务器信息
        public void StartMsg()
        {
            while (!isClose)
            {
                try
                {
                    //发送消息的大小
                    var bytes = new byte[1024 * 1024];
                    var mlength = cilentSocket.Receive(bytes);
                    //将字节转换为字符串
                    string msg = Encoding.UTF8.GetString(bytes, 0, mlength);
                    this.Invoke(new Action(() =>
                    {
                        this.richTextBox1.Text += string.Format("【收到 ← 来自:{0}】:\n{1}\n", DateTime.Now, msg);
                    }));
                }
                catch (Exception ex)
                {   
                    this.Invoke(new Action(() =>
                    {
                        this.richTextBox1.Text += string.Format("连接异常{0}\n", ex.ToString());
                        isClose = true;
                    }));
                }
                
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            //把要发送的字符串转化为字节
            var bytes = Encoding.UTF8.GetBytes(this.txtSend.Text.Trim());
            cilentSocket.Send(bytes);
            this.richTextBox1.Text += string.Format("{0}【发送 → 至 {1}】:\n{2}\n", DateTime.Now,this.ipTex.Text, this.txtSend.Text.ToString().Trim());
            this.txtSend.Text = "";

        }

        private void button1_Click(object sender, EventArgs e)
        {
            isClose = true;
        }
    }
}      

注意事项

  1. 代码是直接可以直接使用的,但是注意这是两个项目的代码,所以需要创建两个项目,一个客户端一个服务端;
  2. 需要为按钮绑定点击事件才可以使事件生效;
  3. 设置ip地址的时候要符合自己网段的ip,否则无法开启服务器,另外也可以使用​

    ​127.0.0.1​

    ​.
  4. 在本项目中客户端与服务端发送消息使用的是字节发送,注意发出的编码与接收的编码要一致,否则无法识别.