我有一个应用程序,我为我的应用程序分发在整个公司,通过我们的Windows 2003服务器(运行IIS 6.0)向我发送数据.小文本消息通过,但包含更多数据(大约20 KB)的更大消息无法通过.
我将字节缓冲区设置为TCP客户端的缓冲区大小.我注意到我的数据正在服务器上收到; 但是,它只通过接收例程循环一次,我的大文件总是与缓冲区大小完全相同,或者是我们服务器上的8 KB.换句话说,我的代码只在服务器关闭套接字连接之前通过一个循环.
考虑到填充整个缓冲区可能存在问题,我尝试将读/写限制为仅1 KB但这只会导致我们的服务器在关闭连接之前收到1 KB后关闭套接字.
我将服务器的错误消息发送回客户端,以便我可以查看它.我从客户端收到的具体错误消息是:
"无法将数据写入传输连接:已建立的连接已被主机中的软件中止."
我更新了我的服务器应用程序,以便底层TCP Socket将使用"keep alives"这一行:
client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
现在,每当我尝试发送消息时,客户端都会收到错误:
"无法将数据写入传输连接:远程主机强制关闭现有连接."
我们的网络管理员告诉我他的内部服务器上没有防火墙或任何端口被阻止.
谷歌搜索错误,我发现帖子暗示人们试图telnet到服务器.我用他们的方向telnet到服务器,但我不知道如何做出响应:
C:> telnet欢迎使用Microsoft Telnet客户端
逃脱角色是'CTRL +]'
Microsoft Telnet> open cpapp 500正在连接到cpapp ...
这就是我得到的.我从来没有得到错误,微软的Telnet屏幕最终会改为"按任意键继续..." - 我想它超时了,但我的代码能以某种方式连接.
我已经在代码和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客户端读取?在完成之前,我是否忽略了设置让Socket保持打开的东西?服务器代码永远不会出现异常,因为TCP客户端永远不会停止,因此我知道没有错误.
我们的网络管理员还没有收到他的会员学位,所以如果结果是服务器的问题,请详细说明如何解决这个问题,因为我们可能不明白你在说什么.
我为此感到抱歉这么久,但我想确保你们那里的人知道我在做什么 - 甚至可能从我的技术中汲取一些信息!
谢谢你的帮助!〜乔
您应该在发送的内容之前加上该内容的长度.你的循环假设所有数据都是在循环执行之前发送的,而实际上你的循环是在数据发送时执行的.有时候线路上没有数据等待,所以循环终止; 同时,内容仍在通过网络发送.这就是你的循环只运行一次的原因.