Jason Gleim
Немного вещей... Программирование сокетов за пределами тривиальных примеров может привести к путанице, поэтому вот что вам нужно знать.
1) Ваш RFID-считыватель должен открыть соединение с сервером на определенном порту. Таким образом, ваш читатель должен быть запрограммирован на отправку сообщений на 192.168.1.12 через порт 9999. В вашем фрагменте кода вы прослушиваете порт 8002. Это одна из причин, по которой вы не получите никаких связей.
2) Если вы находитесь на сервере с несколькими сетевыми картами, вам нужно убедиться, что вы привязываете прослушиватель к правильному. Вы можете использовать Dns.GetHostEntry(Dns.GetHostName())
чтобы получить ваш IPHostEntry, который будет заполнен интерфейсами сервера в элементе AddressList.
The next thing you need to know is to understand the sequence of things when a connection is established. When you create a socket and call Accept or BeingAccept, the socket will wait for a connection from a client. When your reader connects, the socket either returns a new socket or will hit the callback method you provided where you get the new socket with EndAccept. The new socket is the CONNECTED socket for your client and you must call Receive or BeginReceive on the new socket. In the meantime, your original listening socket can go back to listening for a new connection. You can have up to x number of simultaneous connections based on the value you pass to the Listen method on the original socket.
Возвращаясь к новому сокету, подключенному к клиенту, вы либо получаете, либо начинаете получать данные из этого сокета. Вы указываете буфер при вызове этого метода, и когда он возвращается (или попадает в обратный вызов), вы получаете количество полученных байтов. Вы должны получить эти данные, а затем повторить процесс до тех пор, пока не получите все данные и не захотите закрыть соединение.
Последнее предостережение заключается в том, что закрытие сокета приводит к исключению. Это самая глупая вещь, но именно так она работает. Вы также должны закрыть сокеты по порядку, иначе вы рискуете потерять ссылку на подключенный сокет и тем самым утечка памяти до тех пор, пока приложение не закроется.
Я предлагаю вам, если вы не хотите, чтобы пользовательский интерфейс блокировался на вас, выполнить прослушивание рабочего потока. Я поместил свой класс В класс listener, чтобы открыть несколько портов для прослушивания нескольких устройств, создающих прослушиватели с фабрики. В моем коде ниже IPAddress и LIsteningPort являются свойствами класса. Я использую асинхронные методы в сокете, потому что хочу, чтобы пользовательский интерфейс мог закрыть прослушиватель или завершить работу упорядоченным образом. Если бы я использовал методы синхронизации, рабочий поток заблокировался бы, и я застрял бы, убивая поток нелюбезным способом.
Вот три важных метода::
private void _worker_DoWork(object sender, DoWorkEventArgs e)
{
/* WHAT WE ARE DOING:
* To begin, make sure we have valid parameters.
* Check to make sure there isn't already a listener on the same IP/Port
* Create the socket.
* Bind to the socket.
* Wait for a connection then do nothing until the connection closes or the thread is shut down.
*/
BackgroundWorker worker = sender as BackgroundWorker;
// Parameter checking
if (IPAddress == null) throw new ArgumentNullException("IP Address");
if (ListeningPort == 0) throw new ArgumentException("Listening Port");
// Create an endpoint from the ip address and port
IPEndPoint localEndPoint = new IPEndPoint(IPAddress, ListeningPort);
// Create a TCP/IP socket if needed (might be re-used)
_listeningSocket = new Socket(IPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Try to bind the socket...
try
{
if (!_listeningSocket.IsBound)
_listeningSocket.Bind(localEndPoint);
_listeningSocket.Listen(1);
// Clear the stop flag
stopListener.Reset();
_socketState = new SocketStateObject() { RootSocket = _listeningSocket, worker = worker };
worker.ReportProgress(10); // Report that we are running
while (worker.CancellationPending == false)
{
if (!waitingForClient.WaitOne(0) && _socketState.ConnectedSocket == null)
{
// Start an async socket listening for connections...
_listeningSocket.BeginAccept(new AsyncCallback(AcceptSocketCallback), _socketState);
waitingForClient.Set();
}
stopListener.WaitOne(250);
}
// User wants to shut down...
if (_socketState.ConnectedSocket != null)
{
if(_socketState.ConnectedSocket.Connected)
{
_socketState.ConnectedSocket.Shutdown(SocketShutdown.Both);
}
_socketState.ConnectedSocket.Close();
_socketState.ConnectedSocket.Dispose();
// Now close the main listening socket
_listeningSocket.Close();
_listeningSocket.Dispose();
}
if (waitingForClient.WaitOne(0))
{
// If we are waiting for a connection then just end the accept and close the socket.
_listeningSocket.Close();
_listeningSocket.Dispose();
}
RaisePropertyChanged("IsConnected");
RaisePropertyChanged("IsListening");
// Signal that we are stopped
stopListener.Set();
}
catch (ObjectDisposedException ode)
{
// Nothing really to do. This just means the socket was closed.
}
catch (SocketException se)
{
ListenerErrorMsg = $"Unable to open the socket.";
ListenerErrorCode = (int)se.SocketErrorCode;
ListenerException = se;
worker.ReportProgress(0, new ListenerErrorEventArgs(ListenerErrorMsg, ListenerErrorCode, ListenerException));
}
catch (SecurityException sec)
{
ListenerErrorMsg = $"Insufficient security to open the socket.";
ListenerErrorCode = -2;
ListenerException = sec;
worker.ReportProgress(0, new ListenerErrorEventArgs(ListenerErrorMsg, ListenerErrorCode, ListenerException));
}
catch (Exception ex)
{
ListenerErrorMsg = $"Could not bind to the specified socket for an unknown reason.";
ListenerErrorCode = -2;
ListenerException = ex;
worker.ReportProgress(0, new ListenerErrorEventArgs(ListenerErrorMsg, ListenerErrorCode, ListenerException));
}
}
// Accepts a connection on the listening socket
private void AcceptSocketCallback(IAsyncResult ar)
{
SocketStateObject state = ar.AsyncState as SocketStateObject;
// Get the socket that handles the client request.
try
{
Socket listener = state.RootSocket;
Socket handler = listener.EndAccept(ar);
// Create the state object.
state.ConnectedSocket = handler;
handler.BeginReceive(state.buffer, 0, SocketStateObject.BufferSize, 0,
new AsyncCallback(ReadSocketCallback), state);
RaisePropertyChanged("IsConnected");
// Signal the main thread to continue.
waitingForClient.Reset();
}
catch (ObjectDisposedException)
{
// Just eat the exception because it means the socket is closed.
state.RootSocket = null;
RaisePropertyChanged("IsConnected");
}
}
private void ReadSocketCallback(IAsyncResult ar)
{
string content = string.Empty;
StringBuilder sb = new StringBuilder();
// Retrieve the state object and the handler socket
// from the asynchronous state object.
SocketStateObject state = (SocketStateObject)ar.AsyncState;
Socket handler = state.ConnectedSocket;
// Clear the string builder
sb.Clear();
// Read data from the client socket.
try
{
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// Got data back in the message
sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Read the content of the string builder into a string
content = sb.ToString();
// Check to see if the content string has null bytes at the end (arrive as \0). The PLC pads the string with those. :-/
int zeroBytePos = content.IndexOf(Convert.ToChar(0));
if (zeroBytePos > 0)
content = content.Substring(0, zeroBytePos);
// Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
// Set the last message received
LastMessage = content;
state.worker.ReportProgress(50, content);
// Re-trigger on Begin Receive in case there is more.
handler.BeginReceive(state.buffer, 0, SocketStateObject.BufferSize, 0,
new AsyncCallback(ReadSocketCallback), state);
}
}
catch (ObjectDisposedException)
{
// Just eat the exception because it means the socket is closed.
state.ConnectedSocket = null;
RaisePropertyChanged("IsConnected");
}
catch (SocketException)
{
// Probably a closed connection on the far end. We need to go back into accept mode.
if (state.ConnectedSocket.Connected)
{
state.ConnectedSocket.Shutdown(SocketShutdown.Both);
}
state.ConnectedSocket.Close();
state.ConnectedSocket.Dispose();
state.ConnectedSocket = null;
RaisePropertyChanged("IsConnected");
}
}
// State object for reading client data asynchronously
internal class SocketStateObject
{
private readonly Object thisLock = new Object();
private Socket _rootSocket = null;
private Socket _connectedSocket = null;
// Parent socket. This is the one that accepts connections
internal Socket RootSocket
{