文章目录
- TCP 连接掉线自动重连
- 定义
- 使用
- 连接效果
TCP 接收数据时防止掉线。TCP 连接掉线自动重连。多线程环境下TCP掉线自动重连。
欢迎讨论更好的方法!
TCP 连接掉线自动重连
定义
定义一个类,以编写TCP连接函数Connect()
,并且:
初始化时保存TCP连接的基本信息,在重连时不需要再次输入参数;
编写自动重连函数TryToConnect()
internal class Receiver
{
private Socket clientConn;
private string ip, myIP;
private int port;
private EndPoint point, myPoint;
/// <summary>
/// 需要使用锁来防止多线程抢连
/// </summary>
private Mutex mutexConnect = new Mutex(false, "MutexForConnect");
/// <summary>
/// 与交互的执行者
/// </summary>
/// <param name="myIP">本地ip地址字符串</param>
/// <param name="ip">ip地址字符串</param>
/// <param name="port">端口号</param>
public Receiver(in string myIP, in string ip, in int port)
{
// 保存记录
this.myIP = myIP;
this.ip = ip;
this.port = port;
// 设置连接
myPoint = new IPEndPoint(IPAddress.Parse(myIP), 0); // 本地IP,0表示任意端口
point = new IPEndPoint(IPAddress.Parse(ip), port); // 服务器的地址
}
/// <summary>
/// 对Connect函数加锁(因为有多个线程需要连接,会报错)
/// </summary>
/// <returns>若连接成功则返回socket对象,否则返回空</returns>
public Socket TryToConnect()
{
// 如果已连接,直接返回了。
if (!(clientConn is null) && clientConn.Connected) return clientConn;
mutexConnect.WaitOne(); // 阻塞,每次连接一个。等进入者释放锁再进。
// 如果刚才未连接,但是另一个【进入进程】先connect了,那就返回了。
if (!(clientConn is null) && clientConn.Connected) return clientConn;
bool flag = Connect(); // 【进入进程】发起连接
Thread.Sleep(1000); // 防止过于频繁的连接,每秒进一个
mutexConnect.ReleaseMutex(); // 【进入进程】释放锁
return flag ? clientConn : null; // 若连接成功则返回socket对象,否则返回空
}
/// <summary>
/// 建立与服务器的TCP/IP连接
/// </summary>
/// <returns>成功返回true,反之返回false</returns>
public Boolean Connect()
{
Console.Write($"({ip} {port}) 连接中...");
//创建一个新的Socket对象
clientConn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 建立TCP / IP连接
try
{
clientConn.Bind(myPoint); //绑定本地IP,多IP防止串(若无此IP则可能抛出异常)
clientConn.Connect(point); //尝试连接
Console.WriteLine("连接成功");
return true;
}
catch (Exception)
{
Console.WriteLine("连接失败");
clientConn.Close();
clientConn.Dispose();
return false;
}
}
}
使用
此处仅用主线程模拟。但实际上,多个线程使用连接语句也是OK的。
static void Main(string[] args)
{
Receiver receiver = new Receiver(myIP: "192.168.100.10", ip: "192.168.100.1", port: 2003);
// 连接
Socket conn = null;
while (conn is null) conn = receiver.TryToConnect(); // 如果没连上,就阻塞(因为不连上就无法进行后续工作)
// 接收数据
int toReadLen = 20; // 准备接收的byte数据长度
byte[] rawData = new byte[toReadLen]; // 接收数据的byte数组
int len = conn.Receive(rawData, 0, toReadLen, SocketFlags.None); // 接收到扫码器传来的信息
while (len < toReadLen)
len += conn.Receive(rawData, len, toReadLen - len, SocketFlags.None); // 不足时,继续接收直到指定长度
// 此处用于处理接收到的信息
Console.WriteLine(BitConverter.ToString(rawData, 0, len));
Console.ReadLine();
}