我是网络编程的新手,我正在尝试使用NetworkStream(C#)将文件从客户端发送到服务器。
我认为下面的代码应该有效,但有时(随机)接收端(服务器)将永远循环并且不会收到文件(发送似乎工作正常)。
我有一个助理看看学校的代码,他提出了以下修复/黑客:在进入发送文件的循环之前使用Thread.Sleep(500)。他没有向我解释为什么这样有效,他只是说它发生了一些事情,并且原始代码(没有Thread.Sleep(500))应该可以正常工作(有时会这样做)。
虽然这个黑客似乎解决了这个问题,但我对此并不满意,因为我不太明白它为什么会起作用,现在我正在寻找一个更清洁/更强大的解决方案来解决这个问题。
这是我的代码:
SERVER:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace _003
{
class server
{
[STAThread]
static void Main(string[] args)
{
//args = ip, port
try
{
TcpListener myTcpListener = new TcpListener(IPAddress.Parse(args[0]), int.Parse(args[1]));
myTcpListener.Start();
Socket sejaSocket;
while (true)
{
//čakamo na povezavo iz clienta
sejaSocket = myTcpListener.AcceptSocket();
if (sejaSocket.Connected)
{
NetworkStream stream = new NetworkStream(sejaSocket);
StreamWriter sWriter = new StreamWriter(stream);
sWriter.AutoFlush = true;
StreamReader sReader = new StreamReader(stream);
FileStream myFileStream = new FileStream(@"output.file", FileMode.Create, FileAccess.Write);
long rdby = 0;
int len;
byte[] buffed = new byte[1024];
Console.WriteLine("Prejemam datoteko!");
int dolzinaDat = int.Parse(sReader.ReadLine());
while (rdby < dolzinaDat)
{
Console.Write("#");
len = stream.Read(buffed, 0, buffed.Length);
myFileStream.Write(buffed, 0, len);
myFileStream.Flush();
rdby += len;
Console.WriteLine(dolzinaDat + " " + rdby + " " + len.ToString());
};
stream.Close();
myFileStream.Close();
Console.WriteLine();
Console.WriteLine("Prenos končan!");
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
客户端:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace _003
{
class client
{
[STAThread]
static void Main(string[] args)
{
//args = ip, port
try
{
TcpClient sejaTcpClient = new TcpClient();
sejaTcpClient.Connect(IPAddress.Parse(args[0]), int.Parse(args[1]));
NetworkStream stream = sejaTcpClient.GetStream();
StreamWriter sWriter = new StreamWriter(stream);
sWriter.AutoFlush = true;
StreamReader sReader = new StreamReader(stream);
FileStream myFileStream = new FileStream(@"input.file", FileMode.Open, FileAccess.Read);
long rdby = 0;
int len;
byte[] buffed = new byte[1024];
Console.WriteLine("Pošiljam datoteko!");
long dolzinaDat = myFileStream.Length;
sWriter.WriteLine(dolzinaDat);
//UNCOMMENT THIS AND THE CODE WORKS FINE
//Thread.Sleep(500);
while (rdby < dolzinaDat)
{
Console.Write("#");
len = myFileStream.Read(buffed, 0, buffed.Length);
stream.Write(buffed, 0, len);
stream.Flush();
rdby += len;
Console.WriteLine(dolzinaDat + " " + rdby + " " + len.ToString());
}
stream.Close();
myFileStream.Close();
Console.WriteLine();
Console.WriteLine("Prenos končan!");
Console.WriteLine("Pritisni tipko, da končas");
Console.ReadKey(true);
Console.WriteLine("Konec");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
任何帮助都会非常感激!
答案 0 :(得分:1)
您在发送内容之前将文件的长度写为新行。但是,StreamReader.ReadLine可以从单个行的流中读取更多字节。这是因为它进行内部缓冲。要准确读取单行,必须从流中读取单个字节,这是一个效率噩梦。
使用BinaryReader / Writer将文件长度传输为long
。
答案 1 :(得分:1)
您正在使用流直接混合,并通过StreamReader
阅读。 StreamReader
可以缓冲读取。也就是说:它可以从文件中读取比预期更多的内容。这意味着基础Stream
的读取位置可能比您想象的更进一步。
(Sleep
可能导致StreamReader
在读取期间超时,并发现它具有所需的一切。因此它返回时不会使流超出第一行;
直接从底层流中读取而不使用阅读器,或者始终使用阅读器阅读。在这种情况下,你最好使用BinaryReader
,因为你还是要阅读二进制文件。