2009-08-10 210 views
6

我有一个应用程序为我的应用程序编写,分布在整个公司,通过我们的Windows 2003服务器(运行IIS 6.0)向我发送数据。小文本消息可以通过,但包含更多数据(大约20 KB)的大消息无法通过。TCP客户端连接

我将字节缓冲区设置为TCP客户端的缓冲区大小。我注意到我的数据正在服务器上收到;但是,它只通过接收例程循环一次,而我的大文件总是正好是缓冲区大小的大小,或者我们服务器上的大小为8 KB。换句话说,我的代码只在服务器关闭套接字连接之前通过一个循环。

考虑到填充整个缓冲区可能存在问题,我尝试将读/写限制为1 KB,但这仅导致我们的服务器在关闭连接之前收到1 KB后关闭套接字。

我将服务器的错误信息发送回客户端,以便我可以查看它。我从客户端收到特定的错误信息是:

“Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.”

我更新了我的服务器应用程序,使底层TCP套接字将使用的“保持活动”这一行:

client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true); 

现在,每当我试图发送一个消息,在客户端收到错误:

“Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.”

我们的网络管理员告诉我,他没有防火墙或阻止我们内部的服务器上的任意端口。

使用谷歌搜索错误,我发现帖子暗示人们尝试远程登录到服务器。我用自己的方向远程登录到服务器上,但我不知道该做出响应的是什么:

C:> telnet Welcome to Microsoft Telnet Client

Escape Character is ‘CTRL+]’

Microsoft Telnet> open cpapp 500 Connecting To 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客户端阅读?我有没有忽视设置一些东西,告诉套接字在我完成之前保持打开状态?服务器代码从不会看到异常,因为TCP客户端从不停止,所以我知道没有错误。

我们的网络管理员还没有收到他的同事学位,所以如果事实证明是服务器的问题,请在你的描述中详细说明如何解决这个问题,因为我们可能不明白你在说什么。

我很抱歉这么长时间,但我想确保你们在那里知道我在做什么 - 甚至可以从我的技术中获得一些信息!

感谢您的帮助! 〜乔

回答

6

您应该在发送的内容之前加上该内容的长度。你的循环假定所有的数据都是在循环执行之前发送的,而实际上你的循环是在数据发送时执行的。有些时候在线路上没有数据等待,所以循环终止;同时,内容仍然通过电话线传送。这就是为什么你的循环只运行一次。

+0

没有开玩笑吗?我想现在是有道理的。我一直在想,需要在服务器上设置一些东西。这有助于很多*!谢谢! – jp2code 2009-08-12 13:06:29

+0

我该怎么做? “在发送内容之前的内容长度”我没有发送内容的长度? – 2017-11-28 08:26:48

+0

如果你不知道长度,那么显然你不会发送线上的长度。 – Amy 2017-11-28 22:09:03

1

如果我看了你的代码正确,你已经基本上得到了(对不起,C风格 - 我不擅长用C#:

 
do 
{ 
    socket = accept(); 
    read(socket, buffer); 
}while(not_done); 

如果我是正确的,那么它。意味着你需要更多...在那里一点。如果你希望它被序列化,读取每个上传的顺序,你会想要第二个循环:

 
do 
{ 
    socket = accept(); 
    do { read(socket, buffer); not_done_reading=...; } while (not_done_reading); 
}while(not_done); 

如果你想同时放读取多个上传,你需要更多的东西:

 
do 
{ 
    socket = accept(); 
    if(!fork()) 
    { 
    do { read(socket, buffer); not_done_reading=...; } while (not_done_reading); 
    } 
}while(not_done); 
1

你的telnet的例子是有些矛盾的代码,你描述的行为 - 如果你是以往任何时候都能够在服务器上,“远程登录<主机名> <端口号>”上得到任何东西应该让你到空白屏幕相当快(在CMD提示符下的Windows机器上)。所以,这是第一个奇怪的事情 - 最好用wireshark, though进行调试。

代码的角度来看,我认为这可能是问题与服务器上的此内线:

...而((0 < LEN)& &(ns.DataAvailable ==真));

你说你想循环,而你能够阅读的东西,而有一些数据可用。

但是,它可能是第二个段还没有到达服务器,所以没有可用的数据,所以你正在从这个循环中退出。

你应该循环接收数据,而你正在阅读的东西,而没有任何读取错误 - 这保证即使在慢速链接,你会可靠地接收数据。

甲侧面说明:

我注意到你的协议是请求 - 响应 - 请求 - 响应类型。它在局域网上运行良好,但是如果您将来需要在高往返时间链路上工作,这将成为一个巨大的性能瓶颈(用于文件传输的MS SMB协议或TFTP以此方式工作) 。 (免责声明:我没有用C#编写很多代码,因此在解释“DataAvailable()”方法时可能会出错,请参阅此FWIW)。

编辑:上面的答案可能需要根据您的协议进行更正 - 即您需要首先阅读文件的长度,然后阅读该文件 - 因为如果您逐字记录,它会打破你完全设计它的方式。

这就是说,对于TCP,不应该假定发送方的write()操作数与接收方的read()操作数相同 - 在某些情况下可能是这种情况(没有数据包损失,没有纳格尔) - 但在一般情况下,这是不对的。