问题
I have an issue where, depending on the startup order of two network devices, I seem to lose the ability to receive data on one end.
The setup is one small server written in C# (.NET 4.0) that listens to a specific port for data coming from an industrial scanner, communicating over TCP. The scanner connects to the server application just fine, and will send small chunks of data (serial numbers) which the server receives and processes. However, restarting (actually, cycling power, doesn't gracefully close its connection) on the scanner causes the server to stop processing data. The order of events, as well as the crucial network traffic that causes problems goes as follows:
SUCCESS FAILURE
|----------------------| |----------------------|
| SCANNER | SERVER | | SCANNER | SERVER |
|----------------------| |----------------------|
| | Starts | | Starts | |
| Starts | | | | Starts |
| Scan | Received | | Scan | Received |
| Restarts | | | Restarts | |
--------(Network)------- --------(Network)-------
| SYN | | | SYN | |
| | ACK-123 | | | SYN ACK |
| RST - 123 | | | ACK | |
| SYN | | | | |
| | SYN ACK | | | |
| ACK | | | | |
|----------------------| |----------------------|
| Scan | Received | | Scan | !LOST! |
|----------------------| |----------------------|
As you can see, in the SUCCESS scenario, after the scanner restart, the server responds to the SYN with an ACK, and the scanner resets the connection because it realizes it is not in the right stream. The server detects this and gracefully handles it. However, in the FAILURE scenario, the server blissfully responds with a SYN ACK, scanner ACKs, and a new connection is established.
The code doesn't complain about anything, but then my TcpLister/TcpClient never seems to receive any more data, even when it is received and ACKed as seen in Wireshark. Seemingly the TcpListener and handler are still waiting on the old connection for data? I'm new to this level network programming (and relatively new to C# itself), so definitely point out if I'm missing something obvious.
Code snippet of the server:
public void Run()
{
while (!shutdown)
{
shutdown = false; // Reset
listenerServer = new TcpListener(IPAddress.Any, scanner.Address.Port);
try
{
listenerServer.Start();
TcpClient handler = listenerServer.AcceptTcpClient();
while (true)
{
try
{
incomingData = null;
dataBuffer = new Byte[256];
NetworkStream stream = handler.GetStream(); // blocks here
int i;
while ((i = stream.Read(dataBuffer, 0, dataBuffer.Length)) != 0)
{
incomingData += Encoding.ASCII.GetString(dataBuffer, 0, i);
int startIndex = incomingData.IndexOf(startMarker);
int endIndex = incomingData.IndexOf(endMarker);
if (startIndex > -1 && endIndex > -1)
{
string serialData = incomingData.Substring(startIndex + 1, endIndex - startIndex - 1);
scanner.ProcessDataChange(serialData);
}
}
}
catch (IOException e)
{
// Deals with SocketExceptions here...
}
finally
{
handler.Close();
}
}
}
catch (SocketException e)
{
listenerServer.Stop();
listenerServer = null;
}
finally
{
listenerServer.Stop();
listenerServer = null;
}
}
}
回答1:
User @LB (L. B) had answered a question, but deleted it thinking it may have been irrelevant. In fact, it was a great answer to the question, and so I am reposting it here. In the end, I wasn't listening to the new connections that were being made. Should L. B wish to repost his answer I'll gladly accept it.
Repost of L. B's answer
You accept only one connection with TcpClient handler = listenerServer.AcceptTcpClient();
When the first connection is closed you don't accept connections anymore. You should move it into the while loop.
EDIT
This is not a direct answer to you question. But I tried the below code and it works well. If you want, you can try it. I'll remove this answer later.
void Run()
{
TcpListener listener = new TcpListener(IPAddress.Any, 12345);
listener.Start();
Task.Factory.StartNew(() =>
{
while (true)
{
var client = listener.AcceptTcpClient();
Task.Factory.StartNew(() => Handler(client), TaskCreationOptions.LongRunning);
}
}, TaskCreationOptions.LongRunning);
}
void Handler(TcpClient client)
{
using (NetworkStream stream = client.GetStream())
{
var dataBuffer = new Byte[256];
int i;
while ((i = stream.Read(dataBuffer, 0, dataBuffer.Length)) != 0)
{
// Processes data here..
//var s = Encoding.UTF8.GetString(dataBuffer, 0, i);
//Console.Write(s);
}
}
}
回答2:
the usual cause of this type of thing is expecting tcp send and receive boundaries to be preserved. i.e you send a chunk and expect to receive the same chunk on the server. This is not guaranteed to happen, and since you dont show your code I cant tell if you are depending on it
来源:https://stackoverflow.com/questions/13404803/tcplistener-tcpclient-stops-processing-data-under-certain-circumstances