UPDATE:
Из-за проблем с администраторами здесь, на Stackoverflow, я разместил очень урезанную версию той же проблемы на форуме MSDN. Этот текст ниже использовал MyNetworking.dll, но это не проблема. Вот очень узкая клиент-серверная проблема, и проблема точно такая же. Не стесняйтесь попробовать это =)
http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/d3d33eb9-7dce-4313-929e-a8a63d0f1e03
/ UPDATE
Итак, у меня странная ошибка.
Обычно у нас есть DLL, которая обрабатывает наши сети. Давайте назовем это MyNetworking.dll
. Мы используем его везде на наших серверах и клиентах и делаем это в течение 5 лет. До сих пор у меня с этим не было проблем.
У меня есть «XMLPoller», который читает XML из базы данных MySQL, сериализует его в массив byte [] и отправляет его по сети. Эти конкретные XML-сообщения имеют 627 байт в сериализованной форме.
XMLPoller подключается к порту на «удаленном сервере» (который является локальным) и отправляет пакеты по одному за раз. Точно в пакете NBR 105 соединение закрыто. 104 пакета отправляются из XMLPoller и принимаются сервером. 104 х 627 = 65208 байт. Но пакет 105, когда общее количество отправленных байтов было бы 65835, соединение закрывается с этой ошибкой:
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
Это ошибка на сервере . Однако я прошел через XMLPoller (клиент) и вижу, когда отправляются последние 627 байт (таким образом, отправка до 65835 байт), и я не вижу ошибок на клиенте, он проходит отправку без проблем.
ОБНОВЛЕНИЕ 20:15 ШВЕДСКОЕ ВРЕМЯ
Я также получаю эту ошибку в клиенте, когда немного больше отлаживаю:
Unable to read data from the transport connection: An established connection was aborted by the software in your host machine.
Мне кажется, я подтвердил, что в клиенте существует ошибка. Я перебираю код и, прежде чем какие-либо исключения обнаруживаются на сервере, я получаю исключение на клиенте, как указано выше.
/ EndUpdate
Мне кажется, что Сервер никогда не получает его, получая ошибку выше. Сервер закрывает соединение из-за того, что что-то происходит на Клиенте. Однако ошибка на клиенте находится в TCPInput; Поток чтения данных по какой-то причине мертв?
Я ничего не буферизирую в MyNetworking.dll.
Когда я получаю новое соединение на сокете (на сервере), я делаю этот код:
public void setConnected(Socket thisClient)
{
NetworkStream stream = new NetworkStream(thisClient);
socket = thisClient;
output = new TCPOutput(stream, outputHandler,this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), null);
}
catch (Exception e)
{
this.disconnect();
}
}
и затем метод OnDataReceived
(где данные фактически получены):
public void OnDataReceived(IAsyncResult asyn)
{
int nbrRead = 0;
byte[] tmp = null;
try
{
nbrRead = stream.EndRead(asyn);
tmp = new byte[nbrRead];
}
catch (Exception e)
{
// *** HERE IS WHERE THE EXCEPTION IS CAUGHT ***
System.Diagnostics.Debugger.Log(0, "Bla1", e.ToString());
this.disconnect();
}
if (nbrRead > 0)
{
try
{
Array.Copy(inputBuffer, 0, tmp, 0, nbrRead);
}
catch(Exception e)
{
System.Diagnostics.Debugger.Log(0, "Bla2", e.ToString());
this.disconnect();
}
preProcessMessage(tmp);
try
{
stream.BeginRead(inputBuffer, 0, 5000, new AsyncCallback(OnDataReceived), new object());
}
catch(Exception e)
{
System.Diagnostics.Debugger.Log(0, "Bla3", e.ToString());
this.disconnect();
}
}
else
this.disconnect();
}
Прямо сейчас я вроде не в курсе, что происходит ... Есть идеи?
ОБНОВЛЕНИЕ 1:
Код клиента для отправки данных:
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
Обновление 2
Я попытался выполнить очистку исходящего потока от клиента - без эффекта :
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
ОБНОВЛЕНИЕ 3: размещение большего количества кода согласно запросу
Этот код старый, а не симпатичный в мире, я знаю. Но это работает очень хорошо в течение 5 лет, поэтому =)
ClientHandler.cs
(что фактический клиент использует для отправки и т. Д.)
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
/// <summary>
/// Summary description for connectionHandler.
/// </summary>
public class ClientHandler
{
#region Fields (17)
string address;
Connector connector;
DataHandler dataHandler;
int id;
TCPInput input;
int interval;
string localAddress;
IPEndPoint localPoint;
int localPort;
NetworkStream outputStream;
public TTCPClientInterface parent;
int port;
tWorks.tNetworking.Protocol.Protocol protocol;
bool reconnect;
string remoteIP;
Socket socket;
public State state;
#endregion Fields
#region Enums (1)
public enum State {Disconnected,Connecting,Connected}
#endregion Enums
#region Constructors (4)
public ClientHandler(int id, TTCPClientInterface parent, Socket socket, tWorks.tNetworking.Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent, Protocol.Protocol protocol)
{
this.id=id;
this.parent = parent;
this.protocol = protocol;
dataHandler = new DataHandler(protocol, this);
state = State.Disconnected;
}
public ClientHandler(int id, TTCPClientInterface parent, Socket socket)
{
this.id=id;
this.parent = parent;
setConnected(socket);
}
public ClientHandler(int id, TTCPClientInterface parent)
{
this.id=id;
this.parent = parent;
this.protocol = null;
changeState(State.Disconnected);
}
#endregion Constructors
#region Delegates and Events (4)
// Delegates (2)
public delegate void ConnectionLostDelegate(string message);
public delegate void exceptionDelegate(Exception ex);
// Events (2)
public event exceptionDelegate ConnectionFailed;
public event ConnectionLostDelegate ConnectionLostEvent;
#endregion Delegates and Events
#region Methods (17)
// Public Methods (16)
public void connect(string address, int port, int retryInterval, bool reestablish)
{
System.Random rand = new Random();
localPort = rand.Next(40000, 60000);
IPAddress localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; // new IPAddress(Dns.GetHostByName(Dns.GetHostName()).AddressList[0].Address);
connect(address, port, retryInterval, reestablish, localIP.ToString(), localPort);
}
/// <summary>
/// Will connect to the address and port specified. If connection failed a new attempt will be made according to the Interval parameter.
/// If connection is lost attempts to reastablish it will be made if Reestablish is set to true.
/// </summary>
/// <param name="address"></param>
/// <param name="port"></param>
/// <param name="retryInterval"></param>
/// <param name="reestablish"></param>
public void connect(string address, int port, int retryInterval, bool reestablish, string localAddress, int localPort)
{
this.reconnect = reestablish;
this.address = address;
this.port = port;
this.interval = retryInterval;
this.localAddress = localAddress;
this.localPort = localPort;
changeState(State.Connecting);
connector = new Connector(address, port, this, interval, localPoint, reestablish);
connector.Connect();
}
public void disconnect()
{
reconnect = false;
if (connector != null)
{
connector.stopConnecting();
}
setDisconnected();
}
public void dispose()
{
}
public void failedConnect(Exception e)
{
if (ConnectionFailed != null)
ConnectionFailed(e);
}
public int getID()
{
return this.id;
}
public string getIP()
{
return remoteIP;
}
public bool isConnected()
{
return this.state == State.Connected;
}
public void outDataLog(int nbrBytes)
{
parent.outDataLog(nbrBytes, id);
}
public void preProcessMessage(byte[] data)
{
//data = Crypto.Decrypt("a1s2d3", data);
if(protocol != null)
dataHandler.addData(data);
else
processMessage(data);
}
public void processMessage(byte[] data)
{
parent.processMessage(data,this);
}
public bool sendData(byte[] data)
{
if(this.state == State.Connected)
{
if (data != null && data.Length > 0)
{
try
{
//data = Crypto.Encrypt("a1s2d3", data);
outputStream.Write(data, 0, data.Length);
outputStream.Flush();
}
catch(Exception e)
{
System.Diagnostics.Debug.WriteLine("ClientHandler.sendData> " + e.ToString());
}
//parent.outDataLog(data.Length);
}
}
return true;
}
public void setConnected(Socket thisClient)
{
socket = thisClient;
outputStream = new NetworkStream(thisClient);
input = new TCPInput(outputStream, this);
remoteIP = this.socket.RemoteEndPoint.ToString();
changeState(State.Connected);
}
public void setDisconnected()
{
try
{
if (this.state == State.Connected)
{
changeState(State.Disconnected);
//socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
catch { }
if (reconnect)
this.connect(address, port, interval, true, localAddress, localPort);
}
public void stopConnect()
{
connector.stopConnecting();
changeState(State.Disconnected);
}
public override string ToString()
{
string returnString = "(D)";
if(this.state == State.Connected)
returnString = this.getIP();
return returnString;
}
// Private Methods (1)
private void changeState(State state)
{
if (this.state == State.Connected && state == State.Disconnected)
{
if (ConnectionLostEvent != null)
ConnectionLostEvent("Uppkoppling bröts.");
}
this.state = state;
parent.connStateChange(this);
}
#endregion Methods
}
}
Это TCPInput.cs
, который прослушивает входящие данные и передает их ClientHandler (см. Выше):
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace tWorks.tNetworking.tNetworkingCF
{
public class TCPInput
{
NetworkStream stream;
ClientHandler client;
public TCPInput(NetworkStream nS, ClientHandler client)
{
stream = nS;
this.client = client;
Thread t = new Thread(new ThreadStart(run));
t.IsBackground = true;
t.Name = "TCPInput";
t.Start();
}
public void run()
{
bool continueRead = true;
byte[] readBuffer = new byte[32768];
byte[] receivedBuffer = null;
int nbrBytesRead = 0;
int receivedBufferPos = 0;
while(continueRead)
{
try
{
nbrBytesRead = 0;
nbrBytesRead = stream.Read(readBuffer, 0, 10000);
receivedBuffer = new byte[nbrBytesRead];
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when stream.Read: " + e.ToString());
continueRead = false;
}
if(nbrBytesRead > 0)
{
try
{
Array.Copy(readBuffer, 0, receivedBuffer, receivedBufferPos, nbrBytesRead);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine("TCPInput> Exception when Array.Copy: " + e.ToString());
continueRead = false;
}
client.preProcessMessage(receivedBuffer);
}
else
{
// *** I can break here, the nbrOfBytes read is 0 when this whole thing explodes =)
System.Diagnostics.Debug.WriteLine("TCPInput> Number of bytes read == 0! Setting continueRead = false");
continueRead = false;
}
}
client.setDisconnected();
}
}
}