Scoket 是 .Net 常用的一种通讯方式,基于 System.Net.Sockets ,我们可以实现 Socket 通讯的基本功能

Socket 基本概念

网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket

Socket 作用场景
消息的实时发送或接收(如聊天室,消息推送等)

Socket 基本流程

1:服务端监听某个端口

2:客户端向服务端地址和端口发起Socket请求

3:服务器接收连接请求后创建Socket连接,并维护这个连接队列

4:客户端和服务端就建立起了双工同信,客户端与服务端就可以实现彼此发送消息

Socket 基本方法

1.服务端-绑定本地的网络节点(Bind)
把一个地址族中的特定地址赋给socket,例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket

2.服务端-网络监听(Listen)
如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求

3.服务端-Socket请求接收(Accept)
将监听到的请求进行接收,这样一个Socket连接就建立好了

4.客户端-发起Socket请求(Connect)
通过配置服务端的IP地址,端口号等信息,进行Socket的请求

5.消息发送(Send)
实际上,Socket 的消息发送并不是直接将消息直接发送到目标主机,仅仅是把buffer中的数据copy到socket的发送缓冲区中
在适当的时机,会把socket发送缓冲区的数据发送到接收方的socket接受缓冲区

6.消息接收(Receive)
从接收方的socket接受缓冲区中把数据copy到应用程序的buffer中。如果应用程序一直没有调用Receive()读取的话,此数据会一直缓存在相应的socket的接收缓冲区

Socket 实际效果


Socket 具体实现
服务端

    class Program
    {
        static Socket socket = null;
        public static void Main(string[] args)
        { 
            ServerStart();
            Console.ReadKey();
        }
         
        public static void ServerStart()
        {
            //定义一个套接字用于监听客户端发来的消息,包含三个参数(IP4寻址协议,流式连接,Tcp协议)  
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //服务端发送信息需要一个IP地址和端口号  
            IPAddress address = IPAddress.Parse("127.0.0.1");

            //将IP地址和端口号绑定到网络节点point上  
            IPEndPoint point = new IPEndPoint(address, 8888);

            //监听绑定的网络节点  
            socket.Bind(point);

            //将套接字的监听队列长度限制为20
            socket.Listen(int.MaxValue);

            Console.WriteLine($"监听{socket.LocalEndPoint.ToString()}消息开始");

            //利用线程后台执行监听,否则程序会假死
            Thread thread = new Thread(WatchConnecting);
            thread.IsBackground = true;
            thread.Start();
        }

        public static void WatchConnecting()
        {
            Socket connection = null;
            while (true)
            {
                connection = socket.Accept();

                //获取客户端的IP和端口号  
                IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
                int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;

                //让客户显示"连接成功的"的信息  
                string sendmsg = $"连接成功,你的IP:{clientIP},端口{clientPort}";

                SendData(connection, sendmsg);

                //客户端网络结点号
                string remoteEndPoint = connection.RemoteEndPoint.ToString();//ip:port
                //显示与客户端连接情况
                Console.WriteLine(remoteEndPoint + "客户端已连接!");

                Thread thread = new Thread(RecvData);
                thread.IsBackground = true;
                thread.Start(connection);
            }
        }

      
        public static void RecvData(object obj)
        {
            Socket socket = (Socket)obj;
            if (socket == null || socket.Connected == false)
            {
                Console.WriteLine("socket为null,或者未连接到远程计算机");
            }

            try
            {
                while (true)
                {
                    if (socket.Available != 0)//不接收数据量为空的请求
                    {
                        byte[] buffer = new byte[socket.Available];//设置缓冲区大小
                                                                  
                        int receiveNumber = socket.Receive(buffer);

                        string data = Encoding.UTF8.GetString(buffer, 0, receiveNumber);

                        Console.WriteLine($"来自{(socket.RemoteEndPoint as IPEndPoint).Address}:{(socket.RemoteEndPoint as IPEndPoint).Port}的消息:{data}");
                    }
                }
            }
            catch (SocketException ex)
            {
                Console.WriteLine("连接已自动断开" + ex.Message);
            }
        }

        public static void SendData(Socket socket, string msg)
        {
            if (socket == null || socket.Connected == false)
            {
                Console.WriteLine("参数socket为null,或者未连接到远程计算机");
            }

            byte[] buffer = Encoding.UTF8.GetBytes(msg);
            if (buffer == null || buffer.Length == 0)
            {
                Console.WriteLine("参数buffer为null ,或者长度为 0");
            } 
            try
            {
                socket.Send(buffer);
            }
            catch (SocketException)
            {
            }
        }
    }

客户端

   class Program
    {
        static Socket socket;
        static void Main(string[] args)
        {
            socket = ConnectServer("127.0.0.1", 8888);
            while (true)
            {
                var msg = Console.ReadLine();
                SendData(socket, msg); 
            } 
        }


        public static Socket ConnectServer(string ip, int port)
        {
            try
            {
                IPAddress ipAddress = IPAddress.Parse(ip);
                IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port);
                socket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                socket.Connect(ipEndPoint);
                if (socket.Connected == false)
                {
                    Console.WriteLine("连接服务端失败");
                    socket = null;
                }
                else
                {
                    new Thread(RecvData).Start(socket);
                    Console.WriteLine("连接服务端成功");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            return socket;
        }


        public static void SendData(Socket socket, string msg)
        {
            if (socket == null || socket.Connected == false)
            {
                Console.WriteLine("参数socket为null,或者未连接到远程计算机,尝试重新连接");
                socket = ConnectServer("127.0.0.1", 8888);//断线重连
            }

            byte[] buffer = Encoding.UTF8.GetBytes(msg);

            if (buffer == null || buffer.Length == 0)
            {
                Console.WriteLine("参数buffer为null ,或者长度为 0");
            }

            try
            {
                socket.Send(buffer);
            }
            catch (SocketException)
            {
            }
        }


        public static void RecvData(object obj)
        {
            Socket socket = (Socket)obj;

            if (socket == null || socket.Connected == false)
            {
                Console.WriteLine("socket为null,或者未连接到远程计算机,尝试重新连接");
                socket = ConnectServer("127.0.0.1", 8888);//断线重连
            }

            try
            {
                while (true)
                {
                    if (socket.Available != 0)//不接收数据量为空的请求
                    {
                        byte[] buffer = new byte[socket.Available];
                        // 已经有数据等待接收
                        int receiveNumber = socket.Receive(buffer);

                        string data = Encoding.UTF8.GetString(buffer, 0, receiveNumber);
                        Console.WriteLine($"来自{(socket.RemoteEndPoint as IPEndPoint).Address}:{(socket.RemoteEndPoint as IPEndPoint).Port}的消息:{data}");
                    }
                }
            }
            catch (SocketException ex)
            {
                Console.WriteLine("连接已自动断开" + ex.Message);
            }
        }
    }