使用Socket实现局域网内聊天室

Socket的通信方式:
    Socket有TCP和UDP两种通信方式,我们可以根据具体的情况来选择。一般情况下,如果需要数据准确传输、不丢失,则选择TCP;反之,则选择UDP。
  参考文章:
      Socket的TCP和UDP连接

需要提前了解的Socket知识点:

  1. Client端输入的IP都是Server所在电脑的IP
  2. Server最好设置0.0.0.0这样无论迁移到哪个电脑上,都是那台电脑的IP
  3. Client和Server必须在同一个局域网之下,否则不能通信;如果要实现跨局域网通信,需要使用公网IP(通过阿里云等)

整个聊天室的代码分为两个模块:

  1. Server服务器模块:只能有一个,用来存储监听用户发送的内容
  2. Client客户模块:可以有多个,各个用户直接进行收发信息

以下是Server代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Server
{
    class Program
    {
        static Socket socket = null;
        static void Main(string[] args)
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            socket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), 60000));
            socket.Listen(10);
            Console.WriteLine("已启动侦听");
            Task.Run(Connect);
            Console.ReadLine();

        }
        static List<Socket> socketPool = new List<Socket>();
        static Socket acceptSocket = null;
        static void Connect()
        {
            while (true)
            {
                try
                {
                    acceptSocket = socket.Accept();
                    var receiveSocket = acceptSocket;
                    Console.WriteLine($"已接受连接:{receiveSocket.RemoteEndPoint}");
                    socketPool.Add(receiveSocket);
                    Task.Run(Receive);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"连接失败:{ex.Message}");
                }

            }

        }

        static void Receive()
        {
            var receiveSocket = acceptSocket;
            while (true)
            {
                if (receiveSocket == null) continue;
                if (!receiveSocket.Connected) continue;
                try
                {
                    byte[] buffer = new byte[1024];
                    var len = receiveSocket.Receive(buffer);
                    if (len < 1) continue;
                    var msg = Encoding.UTF8.GetString(buffer, 0, len);
                    Console.WriteLine($"来自 {receiveSocket.RemoteEndPoint} 的消息 {msg}");
                    var responseBuffer = Encoding.UTF8.GetBytes($"来自{receiveSocket.RemoteEndPoint} 的消息:{msg}");
                    // receiveSocket.Send(responseBuffer);
                    //清理失效的连接
                    for (int i = socketPool.Count - 1; i >= 0; i--)
                    {
                        if (socketPool[i] == null || !socketPool[i].Connected)
                        {
                            socketPool.RemoveAt(i);
                        }
                    }
                    //广播消息(除了发送消息方之外的,全部广播)
                    foreach (var s in socketPool)
                    {
                        if (s != receiveSocket)
                        {
                            s.Send(responseBuffer);
                        }
                    }
                    buffer = null;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + "\n");
                }


            }

        }
    }
}

以下是Client代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

/// <summary>
/// 客户端
/// </summary>
namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        Socket socket = null;
        public MainWindow()
        {
            InitializeComponent();
            btnConnect.Click += btnConnect_Click;
            btnSend.Click += btnSend_Click;
            Task.Run(Receive);
        }

        private void btnConnect_Click(object sender, RoutedEventArgs e)
        {
            if (socket != null && socket.Connected)
            {
                ShowMessage($"无需重复连接");
                return;
            }
            try
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ShowMessage($"LocalEndPoint={socket.LocalEndPoint},RemoteEndPoint={socket.RemoteEndPoint}");
                var ipEndPoint = new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPort.Text));
                socket.Connect(ipEndPoint);

                if (socket.Connected)
                {
                    ShowMessage($"成功连接到:{socket.RemoteEndPoint}");
                }
            }
            catch (Exception ex)
            {
                ShowMessage($"连接失败:{ex.Message}");
                socket = null;
            }
        }

        private void btnSend_Click(object sender, RoutedEventArgs e)
        {
            if (!socket.Connected)
            {
                ShowMessage($"未连接,无法发送");
                return;
            }
            try
            {
                if (rtxtSend.Text != "")
                {
                    var buffer = Encoding.UTF8.GetBytes(rtxtSend.Text);
                    socket.Send(buffer);
                    ShowMessage($"发送到:{socket.RemoteEndPoint},消息:{rtxtSend.Text}");
                }
                rtxtSend.Text = null;
            }
            catch (Exception ex)
            {
                ShowMessage($"发送失败:{socket.RemoteEndPoint},{ex.Message}");
                socket = null;
            }
        }

        private void Receive()
        {
            while (true)
            {
                if (socket == null) continue;
                if (!socket.Connected) continue;
                try
                {
                    byte[] buffer = new byte[1024];
                    if (buffer != null)
                    {
                        int len = socket.Receive(buffer);
                        if (len < 1) continue;
                        string msg = Encoding.UTF8.GetString(buffer, 0, len);
                        ShowMessage(msg);
                    }
                    buffer = null;
                }
                catch (Exception ex)
                {
                    ShowMessage(ex.Message + "\n");
                    socket = null;
                }
            }
        }
        private void ShowMessage(string msg)
        {
            ///这是Winform的用法
            //子线程调用 
            //if (rtxtLog.InvokeRequired) //c#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的
            //{
            //    rtxtLog.Invoke(new Action(() => rtxtLog.Text += msg + "\n"));
            //}
            //主线程调用
            //else
            //{
            //    rtxtLog.Text += msg + "\n";
            //}
            if (!CheckAccess()) //WPF使用Dispatcher控制对消息泵的访问,而不是让每个控件负责访问UI线程。
            {
                Dispatcher.Invoke(new Action(() => rtxtLog.Text += msg + "\n"));
            }
            //主线程调用
            else
            {
                rtxtLog.Text += msg + "\n";
            }
        }
    }
}
  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值