[C#.NET][Tcp Socket] 利用 Socket 控制 ZeroOne's NaviZOT R4 UHF RFID Reader
這台 Reader 跟之前控制的 Reader 連線方式有點不太一樣,光是與它建立起連線通道就卡了好久,這不筆記一下怎麼可以。
開始之前要先利用 Serial COM Port 定義電腦端的 IP,以及 Port,這裡就不著墨,若有問題請聯絡原廠或供應商。
PS.它無法使用 TCP 介面 來變更 Reader 的設定,所有的設定都是必須透過 Serial 介面(COM Port)設定,然後才能使用 TCP Interface
接下來進入這次的重點,連線程式碼如下:
public bool Connect(string hostIp, int hostPort)
{
if (this.IsConnected)
{
return true;
}
var ipAddress = IPAddress.Parse(hostIp);
var iPEndPoint = new IPEndPoint(ipAddress, hostPort);
var endPoint = (EndPoint)iPEndPoint;
//create TCP/IP socket.
this._clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._clientSocket.Bind(endPoint);
this._clientSocket.Listen(int.MaxValue);
//accept
this._acceptSocket = this._clientSocket.Accept();
this.IsConnected = true;
return this.IsConnected;
}
RemoteEndPoint:代表 Reader 的IP,當我與它建立連線時,它所開啟的 Port。
LocalEndPoint:代表我本機電腦的 IP 以及 port。
離線程式碼如下:
public bool Disconnect()
{
if (!this.IsConnected)
{
return true;
}
this._acceptSocket.Shutdown(SocketShutdown.Both);
this._acceptSocket.Disconnect(false);
this._acceptSocket.Close();
this._acceptSocket = null;
this._clientSocket.Close();
this._clientSocket = null;
this.IsConnected = false;
return !this.IsConnected;
}
PS.建立連限後莫約幾秒後我觀察 Smart Sniff 有封包進來,我也搞不太清楚,Reader 在什麼時間點下拋出這個訊息,我都還沒下命令呢,就算我調用 Socket.Receive 也得不到這資料
我已經習慣 Reader 被動模式是 Server ,電腦是Client,在這裡正好是反過來,所以我卡了很久,所以在這裡需要使用 _acceptSocket 來下達 Command set/get
PS.這樣的連接方式與 Alien Reader 的主動模式很像,[C#.Net][TCP Socket] 利用 Socket 同步方法 監聽 Alien Reader。
接下來處理 Command set/get :
下圖為原廠提供的資料,文件裡沒有寫資料檢查碼的定義,縱使有提供資料格式,但仍無法確定該封包的資料正確性,個人認為這是一個很大的缺憾。
命令送出與接收
public string SendAndReceive(string Data)
{
if (!this.IsConnected)
{
throw new Exception("No Connect");
}
if (string.IsNullOrEmpty(Data))
{
return null;
}
byte[] expect = new byte[] { 13, 10 };//equals:\r\n
byte[] target = new byte[2];
var command = this.Encode.GetBytes(Data);
MemoryStream memoryStream = new MemoryStream();
memoryStream.Write(command, 0, command.Length);
//check last bytes
var start = command.Length - expect.Length;
memoryStream.Seek(start, SeekOrigin.Begin);
memoryStream.Read(target, 0, target.Length);
var compare = expect.SequenceEqual(target);
if (!compare)
{
memoryStream.Seek(0, SeekOrigin.End);
memoryStream.Write(expect, 0, expect.Length);
command = memoryStream.ToArray();
}
SocketError socketError = new SocketError();
var sentLength = 0;
while (true)
{
sentLength += this._acceptSocket.Send(command, 0, command.Length, SocketFlags.None, out socketError);
if (sentLength == command.Length)
{
break;
}
}
Thread.Sleep(100);
return this.Receive();
}
public string Receive()
{
MemoryStream memoryStream = new MemoryStream();
var bufferArray = new byte[256];
var index = 0;
try
{
while (true)
{
var receiveCount = this._acceptSocket.Receive(bufferArray, 0);
index += receiveCount;
memoryStream.Write(bufferArray, 0, receiveCount);
memoryStream.Seek(index, SeekOrigin.Begin);
if (!this._acceptSocket.Poll(10000, SelectMode.SelectRead))
{
break;
}
}
byte[] response = memoryStream.ToArray();
var result = this.Encode.GetString(response, 0, response.Length);
return result;
}
finally
{
memoryStream.Close();
}
}
若使用手冊上寫的命令參數是會失敗的,我也是卡了好久,後來是參考原廠提供的程式,再加上Smart Sniff,觀察封包才能正確得到參數
個人在使用上的問題,在這邊記錄一下。
- 安全性問題。
- 資料封包確認性。
- 封包傳遞機制問題,當我送出一個命令時,它有時候並不會完整回答資料,必須要等下一個命令送出後,才會再補足上次未回答的資料。
- 沒有提供 TCP Interface 參數設定機制。
- 文件資料不可靠。
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET