[C.C++] C#之Socket客户端全过程

1564 0
Honkers 2023-5-12 10:02:22 | 显示全部楼层 |阅读模式
目录

    C#开发Socket客户端C#Socket客户端异步实现
      简易封装使用未实现的几个常用操作
    总结


C#开发Socket客户端

我们先新建一个类:SocketClientAsync。
注意点:
1、由于Socket通讯是发送到缓存区内的数据是覆盖,而不是新的,也就是说如果我们第一次发送的内容是 byte[]{0x11,0x22};而第二次发送的内容是byte[]{0x22}。那么我们的服务端在第二次接受到的数据是byte[]{0x22,0x22}。
所以我们需要在Socket.Send(byte[] mes)方法里面声明
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.Length; i++)
{
    buffer = 0x00;
}起到的作用就是每次在发送新的内容到服务端的时候,会将所有的旧的内容替换掉;
2、关闭连接之前需要将通知服务端停止发送和接受,也就是
this.clientSocket.Shutdown(SocketShutdown.Both);中断套接字连接:通知服务器端或客户端停止接收和发送数据。
通知完成之后如果客户端还连接着再进行自己的连接断开
if (this.clientSocket.Connected)
{
    this.clientSocket.Close();
}
3、具体类的代码见下图,可以直接使用/p>  #region SocketClient客户端
  public class SocketClientAsync
  {
    #region 声明变量
    public string IPAdress;
    public bool connected = false;
    public Socket clientSocket;
    private IPEndPoint hostEndPoint;
    private int Flag = 0;
    private AutoResetEvent autoConnectEvent = new AutoResetEvent(false);
    private SocketAsyncEventArgs lisnterSocketAsyncEventArgs;
    public delegate void StartListeHandler();
    public event StartListeHandler StartListen;
    public delegate void ReceiveMsgHandler(byte[] info, int i);
    public event ReceiveMsgHandler OnMsgReceived;
    private List<SocketAsyncEventArgs> s_lst = new List<SocketAsyncEventArgs>();
    #endregion
    #region 构造函数
    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="hostName"></param>
    /// <param name="port"></param>
    /// <param name="i"></param>
    public SocketClientAsync(string hostName, int port, int i)
    {
      Flag = i;
      IPAdress = hostName;
      IPAddress[] hostAddresses = Dns.GetHostAddresses(hostName);
      this.hostEndPoint = new IPEndPoint(hostAddresses[hostAddresses.Length - 1], port);
      this.clientSocket = new Socket(this.hostEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
    }
    #endregion
    #region 开始连接服务端
    /// <summary>
    /// 连接服务端
    /// </summary>
    /// <returns></returns>
    private bool Connect()
    {
      using (SocketAsyncEventArgs args = new SocketAsyncEventArgs())
      {
        args.UserToken = this.clientSocket;
        args.RemoteEndPoint = this.hostEndPoint;
        args.Completed += new EventHandler<SocketAsyncEventArgs>(this.OnConnect);
        this.clientSocket.ConnectAsync(args);
        bool flag = autoConnectEvent.WaitOne(5000);
        if (this.connected)
        {
          this.lisnterSocketAsyncEventArgs = new SocketAsyncEventArgs();
          byte[] buffer = new byte[1024];
          this.lisnterSocketAsyncEventArgs.UserToken = this.clientSocket;
          this.lisnterSocketAsyncEventArgs.SetBuffer(buffer, 0, buffer.Length);
          this.lisnterSocketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(this.OnReceive);
          this.StartListen();
          return true;
        }
        return false;
      }
    }
    #endregion
    #region 判断有没有连接上服务端
    /// <summary>
    /// 判断有没有连接上
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnConnect(object sender, SocketAsyncEventArgs e)
    {
      this.connected = (e.SocketError == SocketError.Success);
      autoConnectEvent.Set();
    }
    #endregion
    #region 发送数据到服务端
    /// <summary>
    /// 发送
    /// </summary>
    /// <param name="mes"></param>
    public void Send(byte[] mes)
    {
      if (this.connected)
      {
        EventHandler<SocketAsyncEventArgs> handler = null;
        //byte[] buffer = Encoding.Default.GetBytes(mes);
        byte[] buffer = new byte[1024];
        for (int i = 0; i < buffer.Length; i++)
        {
          buffer = 0x00;
        }
        Array.Copy(mes, 0, buffer, 0, mes.Length);
        SocketAsyncEventArgs senderSocketAsyncEventArgs = null;
        lock (s_lst)
        {
          if (s_lst.Count > 0)
          {
            senderSocketAsyncEventArgs = s_lst[s_lst.Count - 1];
            s_lst.RemoveAt(s_lst.Count - 1);
          }
        }
        if (senderSocketAsyncEventArgs == null)
        {
          senderSocketAsyncEventArgs = new SocketAsyncEventArgs();
          senderSocketAsyncEventArgs.UserToken = this.clientSocket;
          senderSocketAsyncEventArgs.RemoteEndPoint = this.clientSocket.RemoteEndPoint;
          if (handler == null)
          {
            handler = delegate(object sender, SocketAsyncEventArgs _e)
            {
              lock (s_lst)
              {
                s_lst.Add(senderSocketAsyncEventArgs);
              }
            };
          }
          senderSocketAsyncEventArgs.Completed += handler;
        }
        senderSocketAsyncEventArgs.SetBuffer(buffer, 0, buffer.Length);
        this.clientSocket.SendAsync(senderSocketAsyncEventArgs);
      }
      else
      {
        this.connected = false;
      }
    }
    #endregion
    #region 监听服务端
    /// <summary>
    /// 监听服务端
    /// </summary>
    public void Listen()
    {
      if (this.connected && this.clientSocket != null)
      {
        try
        {
          (lisnterSocketAsyncEventArgs.UserToken as Socket).ReceiveAsync(lisnterSocketAsyncEventArgs);
        }
        catch (Exception)
        {
        }
      }
    }
    #endregion
    #region 断开服务端的连接
    /// <summary>
    /// 断开连接
    /// </summary>
    /// <returns></returns>
    private int Disconnect()
    {
      int res = 0;
      try
      {
        this.clientSocket.Shutdown(SocketShutdown.Both);
      }
      catch (Exception)
      {
      }
      try
      {
        this.clientSocket.Close();
      }
      catch (Exception)
      {
      }
      this.connected = false;
      return res;
    }
    #endregion
    #region 数据接收
    /// <summary>
    /// 数据接受
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnReceive(object sender, SocketAsyncEventArgs e)
    {
      if (e.BytesTransferred == 0)
      {
        if (clientSocket.Connected)
        {
          try
          {
            this.clientSocket.Shutdown(SocketShutdown.Both);
          }
          catch (Exception)
          {
          }
          finally
          {
            if (this.clientSocket.Connected)
            {
              this.clientSocket.Close();
            }
          }
        }
        byte[] info = new Byte[] { 0 };
        this.OnMsgReceived(info, Flag);
      }
      else
      {
        byte[] buffer = new byte[e.BytesTransferred];
        Buffer.BlockCopy(e.Buffer, 0, buffer, 0, e.BytesTransferred);
        this.OnMsgReceived(buffer, Flag);
        Listen();
      }
    }
    #endregion
    #region 建立连接服务端的方法
    /// <summary>
    /// 建立连接的方法
    /// </summary>
    /// <returns></returns>
    public bool ConnectServer()
    {
      bool flag = false;
      this.StartListen += new StartListeHandler(SocketClient_StartListen);
      // tis.OnMsgReceived += new ReceiveMsgHandler(SocketClient_OnMsgReceived);
      flag = this.Connect();
      if (!flag)
      {
        return flag;
      }
      return true;
    }
    #endregion
    #region 关闭与服务端之间的连接
    /// <summary>
    /// 关闭连接的方法
    /// </summary>
    /// <returns></returns>
    public int CloseLinkServer()
    {
      return this.Disconnect();
    }
    #endregion
    #region 监听方法
    /// <summary>
    /// 监听的方法
    /// </summary>
    private void SocketClient_StartListen()
    {
      this.Listen();
    }
    #endregion
    #region IDispose member
    public void Dispose()
    {
      if (this.clientSocket.Connected)
      {
        this.clientSocket.Close();
      }
    }
    #endregion
    #region 析构函数
    ~SocketClientAsync()
    {
      try
      {
        if (this.clientSocket.Connected)
        {
          this.clientSocket.Close();
        }
      }
      catch
      {
      }
      finally
      {
      }
    }
    #endregion
  }
  #endregion4、然后就是类的调用了
    //声明定义变量
    private SocketClientAsync ClientLink;//客户端连接对象
    private string Client_IP = "127.0.0.1";//服务端IP地址
    private int Client_Port = 12345;//服务端监听的端口号
    private Thread Client_Td;//通讯内部使用线程
    private bool ClientLinkRes = false;//服务器通讯状态标志
    private bool ThreadContinue = true;//线程轮询标志
    private bool isOnline = false;//是否在线标志
    /// <summary>
    /// 启动线程
    /// </summary>
    private void StartServer()
    {
      Client_Td = new Thread(LinkSocketSerFunc);
      Client_Td.Start();
    }
    /// <summary>
    /// 重连服务端线程
    /// </summary>
    private void LinkSocketSerFunc()
    {
      object lockobj = new object();
      int heartBeatCount = 0;
      ClientLink = new SocketClientAsync(Client_IP, Client_Port, 0);
      bool NotFirstIn = false;
      while (ThreadContinue)
      {
        try
        {
          if (!ClientLinkRes)
          {
            isOnline = false;
            if (NotFirstIn)
            {
              ClientLink.CloseLinkServer();
              ClientLink = new SocketClientAsync(Client_IP, Client_Port, 0);
            }
            NotFirstIn = true;
            ClientLink.OnMsgReceived += new SocketClientAsync.ReceiveMsgHandler(Client_OnMsgReceived);//绑定接受到服务端消息的事件
            ClientLinkRes = ClientLink.ConnectServer();
          }
          else
          {
            //此处写通讯成功的逻辑处理
          }
        }
        catch (Exception ex)
        {
          ClientLinkRes = false;
          System.Diagnostics.Debug.WriteLine(ex.ToString());
        }
        Thread.Sleep(1000);
      }
    }
    /// <summary>
    /// 接收消息处理
    /// </summary>
    /// <param name="info"></param>
    /// <param name="num"></param>
    private void Client_OnMsgReceived(byte[] info, int num)
    {
      try
      {
        ClientHeartBeat = 0;
        if (info.Length > 0 && info[0] != 0)//BCR连接错误NO
        {
          //info为接受到服务器传过来的字节数组,需要进行什么样的逻辑处理在此书写便可            
        }
        else
        {
          ClientLinkRes = false;
        }
      }
      catch (Exception ex)
      {
        System.Diagnostics.Debug.WriteLine(ex.ToString());
      }
    }
    /// <summary>
    /// 终止服务
    /// </summary>
    public void StopServer()
    {
      if (ClientLinkRes)
      {
        ThreadContinue = false;
        ClientLink.CloseLinkServer();
        ClientLink.Dispose();
      }
    }这基本的Socket客户端后台就写完了,可以直接复制使用,平时都是用这么去写Socket客户端,分享出来,大家就可以直接使用了!

C#Socket客户端异步实现


简易封装

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace dclient
{
  public delegate void DelegateMsg(object msg);
  public class Client
  {
    private static Socket _clientSocket;
    private static string _server;
    private static int _port;
    public static DelegateMsg OnConnect;
    public static DelegateMsg OnSend;
    public static DelegateMsg OnReceive;
    public static DelegateMsg OnServerDown;
    public static DelegateMsg OnErr;
    public static void Connect()
    {
      try
      {
        _server = System.Configuration.ConfigurationManager.AppSettings["serverIp"];
        _port = int.Parse(System.Configuration.ConfigurationManager.AppSettings["serverPort"]);
        IPEndPoint ip = new IPEndPoint(IPAddress.Parse(_server), _port);
        _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        _clientSocket.BeginConnect(ip, new AsyncCallback(ConnectCallBack), _clientSocket);
      }
      catch (Exception e)
      {
        throw e;
      }
    }
    private static void ConnectCallBack(IAsyncResult iar)
    {
      Socket client = (Socket)iar.AsyncState;
      try
      {
        client.EndConnect(iar);
        OnConnect("已连接");
      }
      catch (SocketException e)
      {
        if (e.ErrorCode == 10061)
        {
          OnErr("服务器程序未运行或服务器端口未开放");
        }
        else
        {
          OnErr(e.Message);
        }
      }
      finally
      {
      }
    }
    public static void Send(string msg)
    {
      if (_clientSocket == null || msg == string.Empty) return;
      msg += "\r\n";
      byte[] data = Encoding.UTF8.GetBytes(msg);
      try
      {
        _clientSocket.BeginSend(data, 0, data.Length, SocketFlags.None, asyncResult =>
        {
          int length = _clientSocket.EndSend(asyncResult);
          OnSend(string.Format("客户端发送消息:{0}", msg));
        }, null);
      }
      catch (Exception e)
      {
        OnErr(e.Message);
      }
    }
    public static void Recive()
    {
      byte[] data = new byte[1024];
      try
      {
        _clientSocket.BeginReceive(data, 0, data.Length, SocketFlags.None,
        asyncResult =>
        {
          try
          {
            int length = _clientSocket.EndReceive(asyncResult);
            OnReceive(string.Format("收到服务器消息:长度:{1},{0}", Encoding.UTF8.GetString(data), length));
            Recive();
          }
          catch (SocketException e)
          {
            if (e.ErrorCode == 10054)
            {
              OnerverDown("服务器已断线");
            }
            else
            {
              OnErr(e.Message);
            }
          }
        }, null);
      }
      catch (Exception ex)
      {
        OnErr(ex.Message);
      }
    }
  }
}
使用

public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
      Client.OnConnect += new DelegateMsg(connect);
      Client.OnSend += new DelegateMsg(send);
      Client.OnReceive += new DelegateMsg(receive);
      Client.OnServerDown += new DelegateMsg(svrdown);
      Client.OnErr += new DelegateMsg(onerr);
    }
    private void Form1_Load(object sender, EventArgs e)
    {
      Client.Connect();
    }
    private void connect(object msg)
    {
      System.Diagnostics.Debug.WriteLine(msg.ToString());
      Client.Send("DALO 发送测试");
      Client.Recive();
    }
    private void send(object msg)
    {
      System.Diagnostics.Debug.WriteLine(msg.ToString());
    }
    private void receive(object msg)
    {
      System.Diagnostics.Debug.WriteLine(msg.ToString());
    }
    private void svrdown(object msg)
    {
      System.Diagnostics.Debug.WriteLine(msg.ToString());
    }
    private void onerr(object msg)
    {
      System.Diagnostics.Debug.WriteLine(msg.ToString());
    }
  }
未实现的几个常用操作

1、接收服务器发送的大数据量的合包。
2、服务器断线后客户端自动检测并重连,需先将_clientSocket释放。
3、心跳包。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持中国红客联盟。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4005
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行