socket实践-第一个入门案例

效果和项目结构

一个服务器端和三个客户端通信效果截图
解决方案截图

Socket类成员方法

  • Bind():绑定终结点
  • Listen():开始监听指定的端口
  • AcceptAsync():接受客户端连接,如果返回Socket对象不为空,说明有客户端连接
  • ConnectAsync():连接服务器端
  • ReceiveAsync():接收消息
  • SendAsync():发送消息

实现

服务器端
  • 第一步:使用指定的地址族、套接字类型和协议new一个socket对象
  • 第二步:通过传入的IP和端口,socket对象与终结点相关联
  • 第三步:监听
  • 第四步:接受客户端,这里递归异步方法,如果Socket不为null,递归执行接收消息的异步方法
  • 第五步:把控制台的输入发送给所有已建立连接的客户端
view code
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SocketUtil
{
    public class SocketServer
    {
        private int _port;
        private string _ip;
        private Socket _listener;
        private List<Socket> sockets = new List<Socket>();

        public SocketServer(int port)
        {
            _ip = "127.0.0.1";
            _port = port;
        }

        public SocketServer(string ip, int port)
        {
            _ip = ip;
            _port = port;
        }

        public async Task StartListening()
        {
            _listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            IPAddress address = IPAddress.Parse(_ip);
            IPEndPoint iPEndPoint = new IPEndPoint(address, _port);

            _listener.Bind(iPEndPoint);
            _listener.Listen(10);            
        }

        public async Task AcceptAsync()
        {
            Socket socket = await _listener.AcceptAsync();
            AcceptAsync();
            if (socket != null)
            {
                sockets.Add(socket);
                Console.WriteLine("当前连接客户端数:" + sockets.Count);

                await ReceiveAsync(socket);
            }
        }

        public async Task ReceiveAsync(Socket socket)
        {
            byte[] byteMsg = new byte[1024 * 1024 * 2];
            int res = await socket.ReceiveAsync(byteMsg, SocketFlags.None);
            ReceiveAsync(socket);
            if (res > 0)
            {
                string msg = Encoding.UTF8.GetString(byteMsg, 0, res);
                Console.WriteLine(msg);
            }
        }

        public async Task SendAsync(string msg)
        {
            byte[] byteMsg = Encoding.UTF8.GetBytes(msg);
            foreach (var socket in sockets)
            {
                await socket.SendAsync(byteMsg, SocketFlags.None);
            }
        }

        public void Close()
        {
            _listener.Shutdown(SocketShutdown.Both);
            _listener.Close();
        }
    }
}

控制台提供程序作为宿主

view code
using SocketUtil;
using System;
using System.Threading.Tasks;

namespace Socket.Server
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("输入:quit,关闭服务器。");
            SocketServer server = new SocketServer(12345);
            await server.StartListening();
            await server.AcceptAsync();
            
            while (true)
            {
                string op = Console.ReadLine();
                if (op == "quit")
                    break;
                else
                    await server.SendAsync(op);
            }
        }
    }
}
客户端
  • 第一步:使用指定的地址族、套接字类型和协议new一个socket对象
  • 第二步:通过传入的IP和端口,socket对象与终结点建立连接(ConnectAsync方法)
  • 第三步:子线程递归执行接收消息的异步方法
  • 第四步:把控制台的输入发送给服务器端
view code
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SocketUtil
{
    public class SocketClient
    {
        private string _ip;

        private int _port;

        private Socket client;

        public SocketClient(int port)
        {
            _ip = "127.0.0.1";
            _port = port;
        }

        public SocketClient(string ip, int port)
        {
            _ip = ip;
            _port = port;
        }

        public async Task StartClient()
        {
            IPAddress ipAddress = IPAddress.Parse(_ip);
            IPEndPoint remoteEP = new IPEndPoint(ipAddress, _port);

            client = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            await client.ConnectAsync(remoteEP);
            Console.WriteLine("已经建立连接。");
        }

        public async Task ReceiveAsync()
        {
            byte[] byteMsg = new byte[1024 * 1024 * 2];
            var res = await client.ReceiveAsync(byteMsg, SocketFlags.None);
            ReceiveAsync();
            if (res > 0)
            {
                string msg = Encoding.UTF8.GetString(byteMsg, 0, res);
                Console.WriteLine(msg);
            }
        }

        public async Task SendAsync(string msg)
        {
            byte[] byteMsg = Encoding.UTF8.GetBytes(msg);
            //client.BeginSend(byteMsg, 0, byteMsg.Length, SocketFlags.None, new AsyncCallback(SendCallback), null);
            await client.SendAsync(byteMsg, SocketFlags.None);
        }

        public void Close()
        {
            client.Shutdown(SocketShutdown.Both);
            client.Close();
        }
    }
}

控制台提供程序作为宿主

view code
using SocketUtil;
using System;
using System.Threading.Tasks;

namespace Socket.Client
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("输入:quit,关闭客户端。");
            SocketClient client = new SocketClient(12345);
            await client.StartClient();

            await Task.Run(() =>
            {
                client.ReceiveAsync();
            });

            while (true)
            {
                string op = Console.ReadLine();
                if (op == "quit")
                    break;
                else
                    await client.SendAsync(op);
            }
        }
    }
}

小记:以上只是简单的例子供参考理解,很多细节问题还需要注意:可以再进一步抽象代码,异常处理,递归异步方法是否带来问题?

posted @ 2020-08-03 23:17  boby,peng  阅读(306)  评论(0)    收藏  举报