我正在开发一个使用TCPListener和TCPClient类通过TCP发送文件的简单应用程序。这是发送文件的代码。
Stop是一个易失性布尔值,可以随时停止进程,WRITE_BUFFER_SIZE可能会在运行时更改(另一个易失性)
while (remaining > 0 && !stop)
{
DateTime current = DateTime.Now;
int bufferSize = WRITTE_BUFFER_SIZE;
buffer = new byte[bufferSize];
int readed = fileStream.Read(buffer, 0, bufferSize);
stream.Write(buffer, 0, readed);
stream.Flush();
remaining -= readed;
// Wait in order to guarantee send speed
TimeSpan difference = DateTime.Now.Subtract(current);
double seconds = (bufferSize / Speed);
int wait = (int)Math.Floor(seconds * 1000);
wait -= difference.Milliseconds;
if (wait > 10)
Thread.Sleep(wait);
}
stream.Close();
这是处理接收方的代码:
do
{
readed = stream.Read(buffer, 0, READ_BUFFER_SIZE);
// write to .part file and flush to disk
outputStream.Write(buffer, 0, readed);
outputStream.Flush();
offset += readed;
} while (!stop && readed > 0);
现在,当速度很低(大约5KBps)时,一切正常,但是,当我提高速度时,接收器大小在从流中读取时更容易引发SocketException。我猜测它与所有数据都可以读取之前关闭的远程套接字有关,但是这样做的正确方法是什么?我该什么时候关闭发送客户端?
我没有在谷歌上找到任何关于文件传输的好例子,我发现的那些与我正在做的事情有类似的实现,所以我想我错过了什么。
编辑:我收到此错误“无法从传输连接中读取数据”。这是一个IOException,其内部异常是SocketException。
我在发送者函数中添加了这个,但是我得到了相同的错误,代码永远不会到达stream.close(),当然tcpclient永远不会真正关闭...所以我现在完全迷失了。
buffer = new byte[1];
client.Client.Receive(buffer);
stream.Close();
答案 0 :(得分:1)
通常,您希望在套接字上设置LINGER选项。在C ++下,这将是SO_LINGER,但在Windows下,这实际上并不像预期的那样工作。你真的想这样做:
取自:http://tangentsoft.net/wskfaq/newbie.html#howclose
C#sharp可能已在其库中对此进行了更正,但我对此表示怀疑,因为它们是基于winsock API构建的。
修改强>
更详细地查看您的代码。我发现你根本没有发送任何标题,所以在接收方你不知道你实际应该读多少字节。知道要读取套接字的字节数使得调试更加容易。请记住,如果不正确关闭套接字,关闭套接字仍然可以剪断最后一位数据。
另外,让缓冲区大小变得不稳定并不是线程安全的,并且真的不会给你带来什么。使用stop作为volatile是安全的,但不要指望它是即时的。换句话说,循环可以在获得更新的stop值之前运行几次。在多处理器机器上尤其如此。
<强> Edit_02:强>
对于TCPClientClass,您希望执行以下操作(据我所知,目前无法访问C#)。
// write all the bytes
// Then do the following
client.client.Shutdown(Shutdown.Send) // This assumes you have access to this protected member
while (stream.read(buffer, 0, READ_BUFFER_SIZE) != 0);
client.close()