网络通讯系列
第五章 【网络通讯】【详细场景下的Demo示例(五)】
第四章 【网络通讯】【DotNetty实现(四)】
第三章 【网络通讯】【SuperSocket实现(三)】
第二章 【网络通讯】【Socket实现(二)】
第一章 【网络通讯】【通讯协议(一)】
前言
介绍使用Socket实现网络通讯。
一、程序设计
不依赖于第三方库,我们使用最原始的Socket来实现上位机客户端。
这一章的目的主要是为了让大家熟悉Socket通讯的原理,后面第三、第四章均是使用开源库实现,也是推荐大家在实际项目中使用的,更加高效、稳定。
要实现客户端,我们需要设计四个接口
分别是连接服务器、断连服务器、发送服务器内容、以及接收服务器内容
其中,接收服务器内容,我们不通过接口实现,而是通过事件通知,因为我们不知道什么时候服务器会发送内容,如果使用接口的话需要多开一个线程不断判断,不太好。
后续优化,在客户端中实现自动断线重连功能、解决连接不存在IP的服务器时时间过长问题(Ping功能)等等,这个会在第五章中的Demo实例中有完整解决方案资源可下载。
二、代码
public class CSocketClient
{
private Thread? mReceiveThread = null; //接收数据线程
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private Socket? __m_hSocket = null; //Socket句柄
private int mPort = 0; //记录本客户端端口号
private string mIP = ""; //记录本客户端IP地址
public delegate void ReceiveDataEvent(string ip, int port, byte[] receive);
public event ReceiveDataEvent? OnReceiveData; //接收到内容事件通知
/// <summary>
/// 连接服务器
/// </summary>
/// <param name="hostAddress"></param>
/// <param name="nHostPort"></param>
/// <returns></returns>
public bool Connect(string hostAddress, int nHostPort)
{
DisConnect();
if (__m_hSocket == null)
{
__m_hSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //定义一个socket对象
}
try
{
mPort = nHostPort;
mIP = hostAddress;
IPAddress sin_addr = IPAddress.Parse(hostAddress);
IPEndPoint endPoint = new IPEndPoint(sin_addr, nHostPort);
__m_hSocket.Connect(endPoint);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
//开启一个新的线程不停的接收服务端发来的消息
mReceiveThread = new Thread(() => OnClientRecvTimer(_cancellationTokenSource.Token));
mReceiveThread.Name = "SockReceive" + mReceiveThread.ManagedThreadId;
mReceiveThread.Start();
return true;
}
/// <summary>
/// 发送服务器数据,字节
/// </summary>
/// <param name="sendBuf">要发送的数据</param>
/// <returns>1:成功 0:失败</returns>
public byte Send(byte[] sendBuf)
{
try
{
if (__m_hSocket == null)
{
return 0;
}
int sendBufLen = sendBuf.Length;
int sendRtn = __m_hSocket.Send(sendBuf, sendBufLen, SocketFlags.None);
sendRtn = __m_hSocket.Send(sendBuf, 0, SocketFlags.None);
return 1;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
return 0;
}
/// <summary>
/// 关闭连接
/// </summary>
public void DisConnect()
{
_cancellationTokenSource.Cancel();
if (__m_hSocket is null)
{
return;
}
try
{
__m_hSocket.Shutdown(SocketShutdown.Both);
Thread.Sleep(10);
__m_hSocket.Close(); //关闭连接
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
/// <summary>
/// 接收服务器数据线程
/// </summary>
/// <param name="clientSocket"></param>
private void OnClientRecvTimer(CancellationToken token)
{
int recvLen = 0;
byte[] mReceiveBufRemote = new byte[1024];
while (!token.IsCancellationRequested)
{
Thread.Sleep(1);
try
{
if (__m_hSocket == null || __m_hSocket.Available <= 0)
{
continue;
}
mReceiveBufRemote = new byte[1024];
recvLen = __m_hSocket.Receive(mReceiveBufRemote, mReceiveBufRemote.Length, 0); //接收数据
if (recvLen > 0)
{
recvLen = 0;
OnReceiveData?.Invoke(mIP, mPort, mReceiveBufRemote);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
Thread.Sleep(100);
}
}
}
}