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[i] = 0x00;
}
起到的作用就是每次在发送新的内容到服务端的时候,会将所有的旧的内容替换掉;
2、关闭连接之前需要将通知服务端停止发送和接受,也就是
this.clientSocket.Shutdown(SocketShutdown.Both);
中断套接字连接:通知服务器端或客户端停止接收和发送数据。
通知完成之后如果客户端还连接着再进行自己的连接断开
if (this.clientSocket.Connected)
{
this.clientSocket.Close();
}
3、具体类的代码见下图,可以直接使用
#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[i] = 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);
// this.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
}
#endregion
4、然后就是类的调用了
//声明定义变量
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)
{
OnServerDown("服务器已断线");
}
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、心跳包。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341