>  기사  >  백엔드 개발  >  C#에서 소켓 프레임워크를 사용하는 방법에 대한 자습서

C#에서 소켓 프레임워크를 사용하는 방법에 대한 자습서

黄舟
黄舟원래의
2017-09-18 11:19:151953검색

최근 프로젝트의 소켓 전송 문제로 인해 이를 연구하고 배운 내용을 요약하고 공유하기로 결정했습니다. 다음 기사에서는 C# .NET에서 소켓의 간단하고 실용적인 프레임워크 사용에 대한 관련 정보를 주로 소개합니다. 기사 샘플 코드를 통한 소개는 매우 자세하므로 도움이 필요한 친구들이 참고할 수 있습니다.

머리말

소켓에 관해서는 모두가 어느 정도 참여했을 것입니다. 초기 컴퓨터 네트워크 과정부터 TCP 프로토콜에 대해 이야기했고 소켓은 프로토콜을 추가로 캡슐화한 것입니다. 개발자 소프트웨어 간의 통신을 더욱 쉽고 쉽게 만듭니다.

이번 주에 공유 주차 공간 잠금 장치 프로젝트를 수락했습니다. 하드웨어와 통신하려면 소켓을 사용해야 합니다. 직설적으로 말하면 잠금 장치에 명령을 보내 열림 또는 닫힘을 제어한 다음 작동 인터페이스를 여는 것을 의미합니다. 테스트 및 사용자의 사용이 편리하도록 앱에 추가합니다. 이것의 핵심은 Socket의 사용입니다. 이 기능을 개발한 후 사용하기가 매우 불편하여 핵심 기능을 추상화하고 이를 프레임워크로 캡슐화하는 데 이틀을 보냈습니다. 최종적으로 이 프레임워크를 사용하여 원래 프로젝트를 재구성했습니다. 소프트웨어의 확장성, 견고성 및 내결함성이 크게 향상됩니다.

제가 굳게 믿는 원칙: 모든 것이 객체입니다

자, 더 이상 말도 안 되는 소리는 그만하고 본문으로 들어가겠습니다

Text:

1. 먼저 Socket의 간단한 사용법에 대해 간단히 설명하겠습니다. C#에서.

1단계: 서버는 특정 포트를 수신합니다.

2단계: 클라이언트는 서버 주소 및 포트에 대한 소켓 연결 요청을 시작합니다.

3단계: 서버는 연결 요청을 받은 후 소켓 연결을 생성하고 이를 유지합니다. 이 연결 대기열.

4단계: 클라이언트와 서버는 양방향 통신(즉, 양방향 통신)을 구축했으며, 클라이언트와 서버는 쉽고 편리하게 서로 정보를 보낼 수 있습니다.

간단한 사용을 위한 구체적인 구현 코드는 프로젝트에 캡슐화해 두었습니다. 간단한 구현을 배우려면 제 소스 코드나 Baidu를 참조하세요

2. 그리고 프레임워크

사실 모든 사람이 프레임워크에 대해 자신만의 이해를 갖고 있기 때문에 프레임워크라고 부르는 것은 다소 무리가 있을 수 있지만, 클래스 라이브러리와 프레임워크의 본질적인 차이점은 무엇입니까? 다 코드야~ 하하, 너무 멀다

우선 모든 코드를 헛되이 넣어보자:

서버 소스 파일:

SocketServer.cs


using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;

namespace Coldairarrow.Util.Sockets
{
 /// <summary>
 /// Socket服务端
 /// </summary>
 public class SocketServer
 {
  #region 构造函数

  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="ip">监听的IP地址</param>
  /// <param name="port">监听的端口</param>
  public SocketServer(string ip, int port)
  {
   _ip = ip;
   _port = port;
  }

  /// <summary>
  /// 构造函数,监听IP地址默认为本机0.0.0.0
  /// </summary>
  /// <param name="port">监听的端口</param>
  public SocketServer(int port)
  {
   _ip = "0.0.0.0";
   _port = port;
  }

  #endregion

  #region 内部成员

  private Socket _socket = null;
  private string _ip = "";
  private int _port = 0;
  private bool _isListen = true;
  private void StartListen()
  {
   try
   {
    _socket.BeginAccept(asyncResult =>
    {
     try
     {
      Socket newSocket = _socket.EndAccept(asyncResult);

      //马上进行下一轮监听,增加吞吐量
      if (_isListen)
       StartListen();

      SocketConnection newClient = new SocketConnection(newSocket, this)
      {
       HandleRecMsg = HandleRecMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleRecMsg),
       HandleClientClose = HandleClientClose == null ? null : new Action<SocketConnection, SocketServer>(HandleClientClose),
       HandleSendMsg = HandleSendMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleSendMsg),
       HandleException = HandleException == null ? null : new Action<Exception>(HandleException)
      };

      newClient.StartRecMsg();
      ClientList.AddLast(newClient);

      HandleNewClientConnected?.Invoke(this, newClient);
     }
     catch (Exception ex)
     {
      HandleException?.Invoke(ex);
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  #endregion

  #region 外部接口

  /// <summary>
  /// 开始服务,监听客户端
  /// </summary>
  public void StartServer()
  {
   try
   {
    //实例化套接字(ip4寻址协议,流式传输,TCP协议)
    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //创建ip对象
    IPAddress address = IPAddress.Parse(_ip);
    //创建网络节点对象包含ip和port
    IPEndPoint endpoint = new IPEndPoint(address, _port);
    //将 监听套接字绑定到 对应的IP和端口
    _socket.Bind(endpoint);
    //设置监听队列长度为Int32最大值(同时能够处理连接请求数量)
    _socket.Listen(int.MaxValue);
    //开始监听客户端
    StartListen();
    HandleServerStarted?.Invoke(this);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  /// <summary>
  /// 所有连接的客户端列表
  /// </summary>
  public LinkedList<SocketConnection> ClientList { get; set; } = new LinkedList<SocketConnection>();

  /// <summary>
  /// 关闭指定客户端连接
  /// </summary>
  /// <param name="theClient">指定的客户端连接</param>
  public void CloseClient(SocketConnection theClient)
  {
   theClient.Close();
  }

  #endregion

  #region 公共事件

  /// <summary>
  /// 异常处理程序
  /// </summary>
  public Action<Exception> HandleException { get; set; }

  #endregion

  #region 服务端事件

  /// <summary>
  /// 服务启动后执行
  /// </summary>
  public Action<SocketServer> HandleServerStarted { get; set; }

  /// <summary>
  /// 当新客户端连接后执行
  /// </summary>
  public Action<SocketServer, SocketConnection> HandleNewClientConnected { get; set; }

  /// <summary>
  /// 服务端关闭客户端后执行
  /// </summary>
  public Action<SocketServer, SocketConnection> HandleCloseClient { get; set; }

  #endregion

  #region 客户端连接事件

  /// <summary>
  /// 客户端连接接受新的消息后调用
  /// </summary>
  public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }

  /// <summary>
  /// 客户端连接发送消息后回调
  /// </summary>
  public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }

  /// <summary>
  /// 客户端连接关闭后回调
  /// </summary>
  public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }

  #endregion
 }
}


using System;
using System.Net.Sockets;
using System.Text;

namespace Coldairarrow.Util.Sockets
{
 /// <summary>
 /// Socket连接,双向通信
 /// </summary>
 public class SocketConnection
 {
  #region 构造函数

  public SocketConnection(Socket socket,SocketServer server)
  {
   _socket = socket;
   _server = server;
  }

  #endregion

  #region 私有成员
  
  private readonly Socket _socket;
  private bool _isRec=true;
  private SocketServer _server = null;
  private bool IsSocketConnected()
  {
   bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
   bool part2 = (_socket.Available == 0);
   if (part1 && part2)
    return false;
   else
    return true;
  }

  #endregion

  #region 外部接口

  /// <summary>
  /// 开始接受客户端消息
  /// </summary>
  public void StartRecMsg()
  {
   try
   {
    byte[] container = new byte[1024 * 1024 * 2];
    _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
    {
     try
     {
      int length = _socket.EndReceive(asyncResult);

      //马上进行下一轮接受,增加吞吐量
      if (length > 0 && _isRec && IsSocketConnected())
       StartRecMsg();

      if (length > 0)
      {
       byte[] recBytes = new byte[length];
       Array.Copy(container, 0, recBytes, 0, length);

       //处理消息
       HandleRecMsg?.Invoke(recBytes, this, _server);
      }
      else
       Close();
     }
     catch (Exception ex)
     {
      HandleException?.Invoke(ex);
      Close();
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
    Close();
   }
  }

  /// <summary>
  /// 发送数据
  /// </summary>
  /// <param name="bytes">数据字节</param>
  public void Send(byte[] bytes)
  {
   try
   {
    _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
    {
     try
     {
      int length = _socket.EndSend(asyncResult);
      HandleSendMsg?.Invoke(bytes, this, _server);
     }
     catch (Exception ex)
     {
      HandleException?.Invoke(ex);
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  /// <summary>
  /// 发送字符串(默认使用UTF-8编码)
  /// </summary>
  /// <param name="msgStr">字符串</param>
  public void Send(string msgStr)
  {
   Send(Encoding.UTF8.GetBytes(msgStr));
  }

  /// <summary>
  /// 发送字符串(使用自定义编码)
  /// </summary>
  /// <param name="msgStr">字符串消息</param>
  /// <param name="encoding">使用的编码</param>
  public void Send(string msgStr,Encoding encoding)
  {
   Send(encoding.GetBytes(msgStr));
  }

  /// <summary>
  /// 传入自定义属性
  /// </summary>
  public object Property { get; set; }

  /// <summary>
  /// 关闭当前连接
  /// </summary>
  public void Close()
  {
   try
   {
    _isRec = false;
    _socket.Disconnect(false);
    _server.ClientList.Remove(this);
    HandleClientClose?.Invoke(this, _server);
    _socket.Close();
    _socket.Dispose();
    GC.Collect();
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  #endregion

  #region 事件处理

  /// <summary>
  /// 客户端连接接受新的消息后调用
  /// </summary>
  public Action<byte[], SocketConnection, SocketServer> HandleRecMsg { get; set; }

  /// <summary>
  /// 客户端连接发送消息后回调
  /// </summary>
  public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }

  /// <summary>
  /// 客户端连接关闭后回调
  /// </summary>
  public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }

  /// <summary>
  /// 异常处理程序
  /// </summary>
  public Action<Exception> HandleException { get; set; }

  #endregion
 }
}


using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Coldairarrow.Util.Sockets
{
 /// <summary>
 /// Socket客户端
 /// </summary>
 public class SocketClient
 {
  #region 构造函数

  /// <summary>
  /// 构造函数,连接服务器IP地址默认为本机127.0.0.1
  /// </summary>
  /// <param name="port">监听的端口</param>
  public SocketClient(int port)
  {
   _ip = "127.0.0.1";
   _port = port;
  }

  /// <summary>
  /// 构造函数
  /// </summary>
  /// <param name="ip">监听的IP地址</param>
  /// <param name="port">监听的端口</param>
  public SocketClient(string ip, int port)
  {
   _ip = ip;
   _port = port;
  }

  #endregion

  #region 内部成员

  private Socket _socket = null;
  private string _ip = "";
  private int _port = 0;
  private bool _isRec=true;
  private bool IsSocketConnected()
  {
   bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
   bool part2 = (_socket.Available == 0);
   if (part1 && part2)
    return false;
   else
    return true;
  }

  /// <summary>
  /// 开始接受客户端消息
  /// </summary>
  public void StartRecMsg()
  {
   try
   {
    byte[] container = new byte[1024 * 1024 * 2];
    _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
    {
     try
     {
      int length = _socket.EndReceive(asyncResult);

      //马上进行下一轮接受,增加吞吐量
      if (length > 0 && _isRec && IsSocketConnected())
       StartRecMsg();

      if (length > 0)
      {
       byte[] recBytes = new byte[length];
       Array.Copy(container, 0, recBytes, 0, length);

       //处理消息
       HandleRecMsg?.Invoke(recBytes, this);
      }
      else
       Close();
     }
     catch (Exception ex)
     {
      HandleException?.Invoke(ex);
      Close();
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
    Close();
   }
  }

  #endregion

  #region 外部接口

  /// <summary>
  /// 开始服务,连接服务端
  /// </summary>
  public void StartClient()
  {
   try
   {
    //实例化 套接字 (ip4寻址协议,流式传输,TCP协议)
    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    //创建 ip对象
    IPAddress address = IPAddress.Parse(_ip);
    //创建网络节点对象 包含 ip和port
    IPEndPoint endpoint = new IPEndPoint(address, _port);
    //将 监听套接字 绑定到 对应的IP和端口
    _socket.BeginConnect(endpoint, asyncResult =>
    {
     try
     {
      _socket.EndConnect(asyncResult);
      //开始接受服务器消息
      StartRecMsg();

      HandleClientStarted?.Invoke(this);
     }
     catch (Exception ex)
     {
      HandleException?.Invoke(ex);
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  /// <summary>
  /// 发送数据
  /// </summary>
  /// <param name="bytes">数据字节</param>
  public void Send(byte[] bytes)
  {
   try
   {
    _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
    {
     try
     {
      int length = _socket.EndSend(asyncResult);
      HandleSendMsg?.Invoke(bytes, this);
     }
     catch (Exception ex)
     {
      HandleException?.Invoke(ex);
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  /// <summary>
  /// 发送字符串(默认使用UTF-8编码)
  /// </summary>
  /// <param name="msgStr">字符串</param>
  public void Send(string msgStr)
  {
   Send(Encoding.UTF8.GetBytes(msgStr));
  }

  /// <summary>
  /// 发送字符串(使用自定义编码)
  /// </summary>
  /// <param name="msgStr">字符串消息</param>
  /// <param name="encoding">使用的编码</param>
  public void Send(string msgStr, Encoding encoding)
  {
   Send(encoding.GetBytes(msgStr));
  }

  /// <summary>
  /// 传入自定义属性
  /// </summary>
  public object Property { get; set; }

  /// <summary>
  /// 关闭与服务器的连接
  /// </summary>
  public void Close()
  {
   try
   {
    _isRec = false;
    _socket.Disconnect(false);
    HandleClientClose?.Invoke(this);
   }
   catch (Exception ex)
   {
    HandleException?.Invoke(ex);
   }
  }

  #endregion

  #region 事件处理

  /// <summary>
  /// 客户端连接建立后回调
  /// </summary>
  public Action<SocketClient> HandleClientStarted { get; set; }

  /// <summary>
  /// 处理接受消息的委托
  /// </summary>
  public Action<byte[], SocketClient> HandleRecMsg { get; set; }

  /// <summary>
  /// 客户端连接发送消息后回调
  /// </summary>
  public Action<byte[], SocketClient> HandleSendMsg { get; set; }

  /// <summary>
  /// 客户端连接关闭后回调
  /// </summary>
  public Action<SocketClient> HandleClientClose { get; set; }

  /// <summary>
  /// 异常处理程序
  /// </summary>
  public Action<Exception> HandleException { get; set; }

  #endregion
 }
}

이상이 프레임워크 코드입니다. 다음으로 사용법을 소개하겠습니다

우선 서버 사용법:


using Coldairarrow.Util.Sockets;
using System;
using System.Text;

namespace Console_Server
{
 class Program
 {
  static void Main(string[] args)
  {
   //创建服务器对象,默认监听本机0.0.0.0,端口12345
   SocketServer server = new SocketServer(12345);

   //处理从客户端收到的消息
   server.HandleRecMsg = new Action<byte[], SocketConnection, SocketServer>((bytes, client, theServer) =>
   {
    string msg = Encoding.UTF8.GetString(bytes);
    Console.WriteLine($"收到消息:{msg}");
   });

   //处理服务器启动后事件
   server.HandleServerStarted = new Action<SocketServer>(theServer =>
   {
    Console.WriteLine("服务已启动************");
   });

   //处理新的客户端连接后的事件
   server.HandleNewClientConnected = new Action<SocketServer, SocketConnection>((theServer, theCon) =>
   {
    Console.WriteLine($@"一个新的客户端接入,当前连接数:{theServer.ClientList.Count}");
   });

   //处理客户端连接关闭后的事件
   server.HandleClientClose = new Action<SocketConnection, SocketServer>((theCon, theServer) =>
   {
    Console.WriteLine($@"一个客户端关闭,当前连接数为:{theServer.ClientList.Count}");
   });

   //处理异常
   server.HandleException = new Action<Exception>(ex =>
   {
    Console.WriteLine(ex.Message);
   });

   //服务器启动
   server.StartServer();

   while (true)
   {
    Console.WriteLine("输入:quit,关闭服务器");
    string op = Console.ReadLine();
    if (op == "quit")
     break;
   }
  }
 }
}

클라이언트 사용법:


using Coldairarrow.Util.Sockets;
using System;
using System.Text;

namespace Console_Client
{
 class Program
 {
  static void Main(string[] args)
  {
   //创建客户端对象,默认连接本机127.0.0.1,端口为12345
   SocketClient client = new SocketClient(12345);

   //绑定当收到服务器发送的消息后的处理事件
   client.HandleRecMsg = new Action<byte[], SocketClient>((bytes, theClient) =>
   {
    string msg = Encoding.UTF8.GetString(bytes);
    Console.WriteLine($"收到消息:{msg}");
   });

   //绑定向服务器发送消息后的处理事件
   client.HandleSendMsg = new Action<byte[], SocketClient>((bytes, theClient) =>
   {
    string msg = Encoding.UTF8.GetString(bytes);
    Console.WriteLine($"向服务器发送消息:{msg}");
   });

   //开始运行客户端
   client.StartClient();

   while (true)
   {
    Console.WriteLine("输入:quit关闭客户端,输入其它消息发送到服务器");
    string str = Console.ReadLine();
    if (str == "quit")
    {
     client.Close();
     break;
    }
    else
    {
     client.Send(str);
    }
   }
  }
 }
}

마지막으로 테스트를 실행합니다. 스크린샷:

요약:

가장 편리한 점은 연결을 생성하는 방법을 캡슐화한다는 것입니다. 사용자는 연결 후 어떤 데이터가 전송되는지, 데이터를 처리하는 방법에만 주의하면 됩니다. 많은 이벤트 처리는 주로 익명 대리인의 사용과 람다 표현식의 사용에 의존합니다.

위 내용은 C#에서 소켓 프레임워크를 사용하는 방법에 대한 자습서의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.