最近用C#写个一个通过树莓派(Raspberry Pi)3B+的蓝牙模块来扫描电子设备。当时实现的时候也是花了些时间。现在把代码整理一下,给需要的人参考一下!
目录
NuGet Packages
首先从NuGet上装几个package
- log4net - 用来记录日志,实在太好用了!
- SSH.NET - 用这个来实现通过SSH和树莓派进行通讯
- System.ValueTuple - 这个是比较新的特新,VS2017默认不支持
接下里,我们就直接看代码。
NetworkPinger
这个class是用来检测能不能ping上树莓派。
public interface INetworkPinger
{
bool CanPing(IPAddress ipAddress, int timeoutMilliseconds = 2000);
}
public class NetworkPinger : INetworkPinger
{
private readonly ILog _logger = LogManager.GetLogger(typeof(NetworkPinger));
public bool CanPing(IPAddress ipAddress, int timeoutMilliseconds = 2000)
{
try
{
_logger.Info($"Try to ping {ipAddress}...");
var ping = new Ping();
var pingReply = ping.Send(ipAddress, timeoutMilliseconds);
if (pingReply == null)
throw new Exception($"PingReply is null.");
if (pingReply.Status != IPStatus.Success)
throw new Exception($"The status of PingReply \"{pingReply.Status}\" is not \"{IPStatus.Success}\".");
_logger.Info($"Succeed in pinging {ipAddress}");
return true;
}
catch (Exception exception)
{
_logger.Warn($"Some error happened while pinging {ipAddress}.\n{exception}");
return false;
}
}
}
SshCommunication
这个class就是调用用Renci.SshNet实现SSH通讯的。
- 在调用参数中,有Func委托,委托也是实现松耦合的一种常用方式
public interface ISshCommunicator : IDisposable
{
void Open();
void Close();
string WriteAndRead(
string command,
int timeoutMilliseconds = SshCommunicator.DefaultReadTimeoutMilliseconds);
string WriteAndRead(
string command,
Func<string, bool> canStopEarlier,
int timeoutMilliseconds = SshCommunicator.DefaultReadTimeoutMilliseconds);
string ReadExistingString();
string Read(
Func<string, bool> canStopEarlier,
int timeoutMilliseconds = SshCommunicator.DefaultReadTimeoutMilliseconds);
}
public class SshCommunicator : ISshCommunicator
{
public const int DefaultReadTimeoutMilliseconds = 5000;
private bool _disposed = false;
private SshClient _sshClient = null;
private ShellStream _shellStream = null;
private readonly ILog _logger = LogManager.GetLogger(typeof(SshCommunicator));
private readonly ConnectionInfo _connectionInfo;
public SshCommunicator(string ipAddress, string userName, string password)
{
_connectionInfo =
new ConnectionInfo(
ipAddress,
userName,
new PasswordAuthenticationMethod(userName, password))
{
Encoding = Encoding.ASCII
};
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
Close();
_disposed = true;
}
public void Open()
{
Close();
_sshClient = new SshClient(_connectionInfo);
_sshClient.Connect();
_shellStream = _sshClient.CreateShellStream("BluetoothctlShell", 512, 128, 1920, 1080, 1024 * 10);
}
public void Close()
{
if (_sshClient == null)
return;
try
{
_logger.Info("Close SSH client...");
_shellStream.Close();
_sshClient.Disconnect();
}
catch (Exception exception)
{
_logger.Warn($"Some error happened while closing SSH client.\n{exception}");
}
finally
{
_shellStream = null;
_sshClient = null;
}
}
public string WriteAndRead(string command, int timeoutMilliseconds = DefaultReadTimeoutMilliseconds)
{
IgnoreExistingStringBeforeWrite();
Write(command);
return Read(timeoutMilliseconds);
}
private void IgnoreExistingStringBeforeWrite()
{
var existingString = ReadExistingString();
if (!string.IsNullOrEmpty(existingString))
_logger.Warn($"Ignore the below existing string before write.\n{existingString}");
}
public string WriteAndRead(
string command,
Func<string, bool> canStopEarlier,
int timeoutMilliseconds = DefaultReadTimeoutMilliseconds)
{
IgnoreExistingStringBeforeWrite();
Write(command);
return Read(canStopEarlier, timeoutMilliseconds);
}
private void Write(string command)
{
_logger.Info($"Write \"{command}\"...");
_shellStream.WriteLine(command);
}
public string Read(int timeoutMilliseconds = DefaultReadTimeoutMilliseconds)
{
_logger.Info($