У меня есть приложение, которое я написал для своего приложения, распределенного по всей компании, для отправки мне данных через наш сервер Windows 2003 (под управлением IIS 6.0). Маленькие текстовые сообщения проходят, но большие сообщения, содержащие больше данных (около 20 КБ), не проходят.
Я установил в байтовом буфере размер буфера клиента TCP. Я заметил, что мои данные были получены на сервере; тем не менее, он только один раз прошел процедуру получения, и мои большие файлы всегда имели размер буфера или 8 КБ на нашем сервере. Другими словами, мой код проходит через один цикл, прежде чем сервер закрывает соединение с сокетом.
Думая, что может быть проблема с заполнением всего буфера, я попытался ограничить чтение / запись всего 1 КБ, но это привело к тому, что наш сервер закрыл сокет после получения 1 КБ до закрытия соединения.
Я отправляю сообщение об ошибке сервера обратно клиенту, чтобы просмотреть его. Конкретное сообщение об ошибке, которое я получаю от клиента:
«Невозможно записать данные в транспорт
соединение: установленное соединение
был прерван программным обеспечением в вашем
хост-машина. ”
Я обновил свое серверное приложение, чтобы базовый сокет TCP использовал «keep alives» со следующей строкой:
client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
Теперь, когда я пытаюсь отправить сообщение, клиент получает сообщение об ошибке:
«Невозможно записать данные в транспорт
соединение: существующее соединение было
принудительно закрывается удаленным хостом. ”
Наш сетевой администратор сказал мне, что у него нет брандмауэра или портов на нашем внутреннем сервере.
Погуглив ошибки, я нашел сообщения, предлагающие людям пытаться подключиться к серверу через telnet. Я использовал их указания, чтобы telnet в сервер, но я не уверен, что сделать из ответа:
C:> telnet Добро пожаловать в Microsoft
Клиент Telnet
Escape-символ ‘CTRL +]’
Microsoft Telnet> open cpapp 500
Подключение к cpapp…
Это все, что я получаю. Я никогда не получаю сообщение об ошибке, и экран Telnet от Microsoft со временем изменится на «Нажмите любую клавишу, чтобы продолжить…» - думаю, время истекло, но мой код каким-то образом может подключиться.
Я пробовал другие порты в коде и через Telnet, включая 25, 80 и 8080. Telnet запускает порт 25, но мое приложение, похоже, читает первый цикл независимо от того, какой порт я ему говорю.
Вот мой код, который работает на клиентах:
int sendUsingTcp(string location) {
string result = string.Empty;
try {
using (FileStream fs = new FileStream(location, FileMode.Open, FileAccess.Read)) {
using (TcpClient client = new TcpClient(GetHostIP, CpAppDatabase.ServerPortNumber)) {
byte[] riteBuf = new byte[client.SendBufferSize];
byte[] readBuf = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream()) {
if ((ns.CanRead == true) && (ns.CanWrite == true)) {
int len;
string AOK = string.Empty;
do {
len = fs.Read(riteBuf, 0, riteBuf.Length);
ns.Write(riteBuf, 0, len);
int nsRsvp = ns.Read(readBuf, 0, readBuf.Length);
AOK = Encoding.ASCII.GetString(readBuf, 0, nsRsvp);
} while ((len == riteBuf.Length) && (-1 < AOK.IndexOf("AOK")));
result = AOK;
return 1;
}
return 0;
}
}
}
} catch (Exception err) {
Logger.LogError("Send()", err);
MessageBox.Show(err.Message, "Message Failed", MessageBoxButtons.OK, MessageBoxIcon.Hand, 0);
return -1;
}
}
Вот мой код, который работает на сервере:
SvrForm.Server = new TcpListener(IPAddress.Any, CpAppDatabase.ServerPortNumber);
void Worker_Engine(object sender, DoWorkEventArgs e) {
BackgroundWorker worker = sender as BackgroundWorker;
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.CompanyName);
if (Directory.Exists(path) == false) Directory.CreateDirectory(path);
Thread.Sleep(0);
string eMsg = string.Empty;
try {
SvrForm.Server.Start();
do {
using (TcpClient client = SvrForm.Server.AcceptTcpClient()) { // waits until data is avaiable
if (worker.CancellationPending == true) return;
client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
string location = Path.Combine(path, string.Format("Acp{0:yyyyMMddHHmmssff}.bin", DateTime.Now));
byte[] buf = new byte[client.ReceiveBufferSize];
try {
using (NetworkStream ns = client.GetStream()) {
if ((ns.CanRead == true) && (ns.CanWrite == true)) {
try {
int len;
byte[] AOK = Encoding.ASCII.GetBytes("AOK");
using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write)) {
do {
len = ns.Read(buf, 0, client.ReceiveBufferSize);
fs.Write(buf, 0, len);
ns.Write(AOK, 0, AOK.Length);
} while ((0 < len) && (ns.DataAvailable == true));
}
byte[] okBuf = Encoding.ASCII.GetBytes("Message Received on Server");
ns.Write(okBuf, 0, okBuf.Length);
} catch (Exception err) {
Global.LogError("ServerForm.cs - Worker_Engine(DoWorkEvent)", err);
byte[] errBuf = Encoding.ASCII.GetBytes(err.Message);
ns.Write(errBuf, 0, errBuf.Length);
}
}
}
}
worker.ReportProgress(1, location);
}
} while (worker.CancellationPending == false);
} catch (SocketException) {
// See MSDN: Windows Sockets V2 API Error Code Documentation for detailed description of error code
e.Cancel = true;
} catch (Exception err) {
eMsg = "Worker General Error:\r\n" + err.Message;
e.Cancel = true;
e.Result = err;
} finally {
SvrForm.Server.Stop();
}
}
Почему мое приложение не продолжает чтение с TCP-клиента? Я забыл установить что-то, что говорит Сокету, чтобы оставаться открытым, пока я не закончил? Код сервера никогда не видит исключения, поскольку клиент TCP никогда не останавливается, поэтому я знаю, что ошибки нет.
Наш сетевой администратор еще не получил свою степень Associates Degree, поэтому, если окажется, что это проблема с Сервером, пожалуйста, подробно опишите в вашем описании, как решить эту проблему, потому что мы можем не понимать, что вы говорите.
Я прошу прощения за то, что так долго, но я хочу убедиться, что вы, ребята, знаете, что я делаю - и, возможно, даже высвободить некоторую информацию из моей техники!
Спасибо за помощь!
~ Джо