tutorial on using the socket framework in C #

Source: Internet
Author: User
Recently a project because to use the socket transmission problem, so decided to learn a bit, the content of their own learning to share, the following article is mainly about C #. NET socket simple practical framework used in the relevant information, the text through the sample code introduced in very detailed, need to refer to the friend.





Objective



When it comes to sockets, presumably everyone is involved, from the initial computer network course, the TCP protocol is described, and the socket is a further encapsulation of the protocol, so that our developers can more easily communicate between the software.



This week just accept a shared parking lock project, you need to use the socket and hardware to communicate control, in other words, give the lock to send instructions, control its open or close, and then open to the app interface to make it easy to test and user's use. The core of this is the use of sockets, and then developed this function, I found that the use is very inconvenient, and took 2 days to abstract its core functions and packaging into a framework, and finally use this framework to reconstruct the original project and on-line, greatly improving the software's scalability, robustness, tolerance rate.



The principle of personal conviction: all things are objects



Okay, no more nonsense, down into the text.



Body:



1, first of all, simply talk about the simple use of sockets in C #.



The first step: the server listens to a port



Step Two: The client initiates a socket connection request to the server-side address and port



Step three: Create a socket connection after the server receives the connection request and maintain the connection queue.



The fourth step: the client and the server have established duplex communication (i.e. two-way communication), the client and the server can easily send each other information.



As for the simple use of the implementation of the code is all encapsulated in the project, if you need to learn a simple implementation, you can see my source code, you can also Baidu, there are a lot of tutorials



2, the core, the use of the framework



In fact, it may be a bit farfetched to say that it is a framework, because everyone has their own understanding of the framework, but what is the essential difference between a class library and a framework? All is code ~ haha, pull away



First, empty say no, first put all the code:



Server-side source files:



SocketServer.cs


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

namespace Coldairarrow.Util.Sockets
{
 /// <summary>
 /// Socket server
 /// </ summary>
 public class SocketServer
 {
  #region Constructor

  /// <summary>
  /// Constructor
  /// </ summary>
  /// <param name = "ip"> listening IP address </ param>
  /// <param name = "port"> port to listen to </ param>
  public SocketServer (string ip, int port)
  {
   _ip = ip;
   _port = port;
  }

  /// <summary>
  /// Constructor, listening IP address defaults to this machine 0.0.0.0
  /// </ summary>
  /// <param name = "port"> port to listen to </ param>
  public SocketServer (int port)
  {
   _ip = "0.0.0.0";
   _port = port;
  }

  #endregion

  #region internal members

  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);

      // Immediately perform the next round of monitoring to increase throughput
      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 External interface

  /// <summary>
  /// Start the service and listen to the client
  /// </ summary>
  public void StartServer ()
  {
   try
   {
    // Instantiate the socket (ip4 addressing protocol, streaming, TCP protocol)
    _socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    // Create ip object
    IPAddress address = IPAddress.Parse (_ip);
    // Create a network node object containing ip and port
    IPEndPoint endpoint = new IPEndPoint (address, _port);
    // bind the listening socket to the corresponding IP and port
    _socket.Bind (endpoint);
    // Set the listen queue length to the maximum value of Int32 (can handle the number of connection requests at the same time)
    _socket.Listen (int.MaxValue);
    // Start listening client
    StartListen ();
    HandleServerStarted? .Invoke (this);
   }
   catch (Exception ex)
   {
    HandleException? .Invoke (ex);
   }
  }

  /// <summary>
  /// list of all connected clients
  /// </ summary>
  public LinkedList <SocketConnection> ClientList {get; set;} = new LinkedList <SocketConnection> ();

  /// <summary>
  /// close the specified client connection
  /// </ summary>
  /// <param name = "theClient"> the specified client connection </ param>
  public void CloseClient (SocketConnection theClient)
  {
   theClient.Close ();
  }

  #endregion

  #region public events

  /// <summary>
  /// exception handler
  /// </ summary>
  public Action <Exception> HandleException {get; set;}

  #endregion

  #region server events

  /// <summary>
  /// Executed after the service starts
  /// </ summary>
  public Action <SocketServer> HandleServerStarted {get; set;}

  /// <summary>
  /// Executed when a new client connects
  /// </ summary>
  public Action <SocketServer, SocketConnection> HandleNewClientConnected {get; set;}

  /// <summary>
  /// Executed after the server closes the client
  /// </ summary>
  public Action <SocketServer, SocketConnection> HandleCloseClient {get; set;}

  #endregion

  #region Client connection events

  /// <summary>
  /// Called after the client connection accepts a new message
  /// </ summary>
  public Action <byte [], SocketConnection, SocketServer> HandleRecMsg {get; set;}

  /// <summary>
  /// callback after client connection sends a message
  /// </ summary>
  public Action <byte [], SocketConnection, SocketServer> HandleSendMsg {get; set;}

  /// <summary>
  /// callback when the client connection is closed
  /// </ summary>
  public Action <SocketConnection, SocketServer> HandleClientClose {get; set;}

  #endregion
 }
}


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

namespace Coldairarrow.Util.Sockets
{
 /// <summary>
 /// Socket connection, two-way communication
 /// </ summary>
 public class SocketConnection
 {
  #region Constructor

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

  #endregion

  #region Private Member
  
  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 External interface

  /// <summary>
  /// Start accepting client messages
  /// </ 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);

      // Immediately proceed to the next round of acceptance to increase throughput
      if (length> 0 && _isRec && IsSocketConnected ())
       StartRecMsg ();

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

       // Process the message
       HandleRecMsg? .Invoke (recBytes, this, _server);
      }
      else
       Close ();
     }
     catch (Exception ex)
     {
      HandleException? .Invoke (ex);
      Close ();
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException? .Invoke (ex);
    Close ();
   }
  }

  /// <summary>
  /// send data
  /// </ summary>
  /// <param name = "bytes"> data 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>
  /// Send string (UTF-8 encoding is used by default)
  /// </ summary>
  /// <param name = "msgStr"> string </ param>
  public void Send (string msgStr)
  {
   Send (Encoding.UTF8.GetBytes (msgStr));
  }

  /// <summary>
  /// send string (use custom encoding)
  /// </ summary>
  /// <param name = "msgStr"> string message </ param>
  /// <param name = "encoding"> Encoding used </ param>
  public void Send (string msgStr, Encoding encoding)
  {
   Send (encoding.GetBytes (msgStr));
  }

  /// <summary>
  /// pass in custom attributes
  /// </ summary>
  public object Property {get; set;}

  /// <summary>
  /// close the current connection
  /// </ 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 event handling

  /// <summary>
  /// Called after the client connection accepts a new message
  /// </ summary>
  public Action <byte [], SocketConnection, SocketServer> HandleRecMsg {get; set;}

  /// <summary>
  /// callback after client connection sends a message
  /// </ summary>
  public Action <byte [], SocketConnection, SocketServer> HandleSendMsg {get; set;}

  /// <summary>
  /// callback when the client connection is closed
  /// </ summary>
  public Action <SocketConnection, SocketServer> HandleClientClose {get; set;}

  /// <summary>
  /// exception handler
  /// </ 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 client
 /// </ summary>
 public class SocketClient
 {
  #region Constructor

  /// <summary>
  /// Constructor, the connection server IP address defaults to this machine 127.0.0.1
  /// </ summary>
  /// <param name = "port"> port to listen to </ param>
  public SocketClient (int port)
  {
   _ip = "127.0.0.1";
   _port = port;
  }

  /// <summary>
  /// Constructor
  /// </ summary>
  /// <param name = "ip"> listening IP address </ param>
  /// <param name = "port"> port to listen to </ param>
  public SocketClient (string ip, int port)
  {
   _ip = ip;
   _port = port;
  }

  #endregion

  #region internal members

  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>
  /// Start accepting client messages
  /// </ 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);

      // Immediately proceed to the next round of acceptance to increase throughput
      if (length> 0 && _isRec && IsSocketConnected ())
       StartRecMsg ();

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

       // Process the message
       HandleRecMsg? .Invoke (recBytes, this);
      }
      else
       Close ();
     }
     catch (Exception ex)
     {
      HandleException? .Invoke (ex);
      Close ();
     }
    }, null);
   }
   catch (Exception ex)
   {
    HandleException? .Invoke (ex);
    Close ();
   }
  }

  #endregion

  #region External interface

  /// <summary>
  /// Start the service and connect to the server
  /// </ summary>
  public void StartClient ()
  {
   try
   {
    // Instantiate socket (ip4 addressing protocol, streaming, TCP protocol)
    _socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    // create ip object
    IPAddress address = IPAddress.Parse (_ip);
    // Create a network node object including ip and port
    IPEndPoint endpoint = new IPEndPoint (address, _port);
    // bind the listening socket to the corresponding IP and port
    _socket.BeginConnect (endpoint, asyncResult =>
    {
     try
     {
      _socket.EndConnect (asyncResult);
      // Start accepting server messages
      StartRecMsg ();

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

  /// <summary>
  /// send data
  /// </ summary>
  /// <param name = "bytes"> data 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>
  /// Send string (UTF-8 encoding is used by default)
  /// </ summary>
  /// <param name = "msgStr"> string </ param>
  public void Send (string msgStr)
  {
   Send (Encoding.UTF8.GetBytes (msgStr));
  }

  /// <summary>
  /// send string (use custom encoding)
  /// </ summary>
  /// <param name = "msgStr"> string message </ param>
  /// <param name = "encoding"> Encoding used </ param>
  public void Send (string msgStr, Encoding encoding)
  {
   Send (encoding.GetBytes (msgStr));
  }

  /// <summary>
  /// pass in custom attributes
  /// </ summary>
  public object Property {get; set;}

  /// <summary>
  /// close the connection to the server
  /// </ summary>
  public void Close ()
  {
   try
   {
    _isRec = false;
    _socket.Disconnect (false);
    HandleClientClose? .Invoke (this);
   }
   catch (Exception ex)
   {
    HandleException? .Invoke (ex);
   }
  }

  #endregion

  #region event handling

  /// <summary>
  /// callback after the client connection is established
  /// </ summary>
  public Action <SocketClient> HandleClientStarted {get; set;}

  /// <summary>
  /// Delegate that accepts the message
  /// </ summary>
  public Action <byte [], SocketClient> HandleRecMsg {get; set;}

  /// <summary>
  /// callback after client connection sends a message
  /// </ summary>
  public Action <byte [], SocketClient> HandleSendMsg {get; set;}

  /// <summary>
  /// callback when the client connection is closed
  /// </ summary>
  public Action <SocketClient> HandleClientClose {get; set;}

  /// <summary>
  /// exception handler
  /// </ summary>
  public Action <Exception> HandleException {get; set;}

  #endregion
 }
}
Above is the framework code, let ’s introduce how to use it.

First, the server uses:



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

namespace Console_Server
{
 class Program
 {
  static void Main (string [] args)
  {
   // Create a server object, default listening on the local 0.0.0.0, port 12345
   SocketServer server = new SocketServer (12345);

   // Process the message received from the client
   server.HandleRecMsg = new Action <byte [], SocketConnection, SocketServer> ((bytes, client, theServer) =>
   {
    string msg = Encoding.UTF8.GetString (bytes);
    Console.WriteLine ($ "Received message: {msg}");
   });

   // Handle events after server startup
   server.HandleServerStarted = new Action <SocketServer> (theServer =>
   {
    Console.WriteLine ("The service is started **************");
   });

   // Handle events after a new client connection
   server.HandleNewClientConnected = new Action <SocketServer, SocketConnection> ((theServer, theCon) =>
   {
    Console.WriteLine ($ @ "A new client access, the current number of connections: {theServer.ClientList.Count}");
   });

   // Handle events after the client connection is closed
   server.HandleClientClose = new Action <SocketConnection, SocketServer> ((theCon, theServer) =>
   {
    Console.WriteLine ($ @ "A client is closed, the current number of connections is: {theServer.ClientList.Count}");
   });

   // Handle the exception
   server.HandleException = new Action <Exception> (ex =>
   {
    Console.WriteLine (ex.Message);
   });

   // Server starts
   server.StartServer ();

   while (true)
   {
    Console.WriteLine ("Enter: quit, shut down the server");
    string op = Console.ReadLine ();
    if (op == "quit")
     break;
   }
  }
 }
}
Client usage:



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

namespace Console_Client
{
 class Program
 {
  static void Main (string [] args)
  {
   // Create a client object, the default connection is 127.0.0.1, and the port is 12345
   SocketClient client = new SocketClient (12345);

   // Bind the processing event after receiving the message sent by the server
   client.HandleRecMsg = new Action <byte [], SocketClient> ((bytes, theClient) =>
   {
    string msg = Encoding.UTF8.GetString (bytes);
    Console.WriteLine ($ "Received message: {msg}");
   });

   // Binding processing event after sending a message to the server
   client.HandleSendMsg = new Action <byte [], SocketClient> ((bytes, theClient) =>
   {
    string msg = Encoding.UTF8.GetString (bytes);
    Console.WriteLine ($ "Send message to server: {msg}");
   });

   // Start running the client
   client.StartClient ();

   while (true)
   {
    Console.WriteLine ("Enter: quit to close the client and enter other messages to send to the server");
    string str = Console.ReadLine ();
    if (str == "quit")
    {
     client.Close ();
     break;
    }
    else
    {
     client.Send (str);
    }
   }
  }
 }
}
Finally run the test:

to sum up:

The most convenient point is how to create a connection and encapsulate it. The user only needs to pay attention to what data is sent after the connection, what should be done after receiving the data, and so on. Many other events are processed, which mainly rely on anonymous delegation. Use, the use of Lambda expressions.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.