我尝试将文件从TCPClient发送到具有1000字节缓冲区的TCPListener。 TCPClient位于一个应用程序"服务器"并且TCPListener位于另一个应用程序" client"中。在测试时,两者都在localhost上运行。 我的问题是NetworkStream.Write方法卡住了(参见截图和代码)。我不知道为什么。谷歌搜索后我怀疑套接字缓冲区已满。所以我将WriteTimeout设置为3000毫秒来处理问题。但我无法找到一个刷新方法,以防万一缓冲区出现问题。我该怎么办?
服务器代码(卡在NetworkStream.Write中的代码):
private void fetchThreadMethod(Object commandArgs)
{
byte[] buffer = new byte[1000];
byte[] comMessage = new byte[35];
IPEndPoint localEP = new IPEndPoint(localIP,1304);
TcpClient client = new TcpClient(localEP);
client.Connect(localIP,1305);
Thread.Sleep(1000);
Console.WriteLine("SERVER: Connected to client.");
NetworkStream nStream = client.GetStream();
client.NoDelay = true;
client.Client.NoDelay = true;
nStream.WriteTimeout = 3000;
FileCollector fCollector = new FileCollector();
String currUserVar = Environment.GetEnvironmentVariable("USERPROFILE");
fCollector.startFileCollector(currUserVar + "\\" + commandArgs);
List<FileNode> collectedFiles = fCollector.getCollectedFiles();
ulong byteCount = 0;
FileStream fStream = null;
foreach (FileNode fNode in collectedFiles)
{
String filePath = fNode.getFileName();
try
{
fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
}
catch (Exception e)
{
Console.WriteLine("SERVER: Exception when opening file " + filePath + " with a FileStream.");
continue;
}
FileInfo fInfo = new FileInfo(fNode.getFileName());
String fileHeaderStr = null;
String fileName = fNode.getFileName().Split('\\').Last();
ulong fileSize = (ulong) fInfo.Length;
fileHeaderStr = "FHEAD" + fileName + "FNAME" + fileSize.ToString() + "FSIZE";
byte[] fileHeaderStrBytes = Encoding.ASCII.GetBytes(fileHeaderStr);
byte[] fileHeader = new byte[400];
for(int i = 0; i < fileHeaderStrBytes.Length; i++)
fileHeader[i] = fileHeaderStrBytes[i];
ulong sentBytesCount = 0;
String comStr = String.Empty;
byte readByte = 0;
int readByteInt = 0;
while(sentBytesCount < fileSize)
{
Console.WriteLine("SERVER: Waiting for CLIENT_READY.");
while (!comStr.Equals("CLIENT_READY"))
{
nStream.Read(comMessage, 0, 35);
comStr = Encoding.ASCII.GetString(comMessage).Split(new String[] { "ENDC" }, StringSplitOptions.None)[0];
}
Console.WriteLine("SERVER: Received CLIENT_READY.");
if (sentBytesCount == 0)
{
for (int j = 0; j < 400; j++)
buffer[j] = fileHeader[j];
for(int k = 400; k < 1000; k++)
{
readByteInt = fStream.ReadByte();
if (readByteInt != -1)
{
readByte = Convert.ToByte(readByteInt);
buffer[k] = readByte;
sentBytesCount++;
}
else{
buffer[k] = 0;
}
}
}
else
{
for(int l = 0; l < 1000; l++)
{
readByteInt = fStream.ReadByte();
if (readByteInt != -1)
{
readByte = Convert.ToByte(readByteInt);
buffer[l] = readByte;
sentBytesCount++;
}
else
{
buffer[l] = 0;
}
}
}
try
{
Console.WriteLine("SERVER: Writing to network stream...");
// Gets stuck here! Timeout set to 3000 ms. Throws cought IOException.
nStream.Write(buffer, 0, 1000);
Console.WriteLine("SERVER: Wrote to network stream.");
}catch(IOException ioe)
{
Console.WriteLine("SERVER: Network stream write timed out.");
// ??? What should I do here? ???
}
}
Console.WriteLine("SERVER: File sent:" + fileName);
}
Console.WriteLine("SERVER: All accessible files downloaded from " + (String) commandArgs);
}
客户端代码,即接收等待卡住服务器的文件的代码:
private void fetchFilesThreadMethod()
{
IPEndPoint localEP = new IPEndPoint(localIP, 1305);
TcpListener listener = new TcpListener(localEP);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream nStream = client.GetStream();
byte[] buffer = new byte[1000];
byte[] comMessage = new byte[35];
byte[] comMessageBytes = Encoding.ASCII.GetBytes("CLIENT_READYENDC");
for (int i = 0; i < comMessageBytes.Length; i++)
comMessage[i] = comMessageBytes[i];
ulong bytesRecCount = 0;
ulong fileSize = 0;
ulong bytesLeft = 0;
String fileName = null;
while (true)
{
nStream.Write(comMessage, 0, 35);
Console.WriteLine("CLIENT: Sent CLIENT_READY.");
nStream.Read(buffer, 0, 1000);
byte[] headerBytes = new byte[400];
for (int j = 0; j < 400; j++)
headerBytes[j] = buffer[j];
String headerStr = Encoding.ASCII.GetString(headerBytes);
if (headerStr.Contains("FHEAD") || headerStr.Contains("FNAME") || headerStr.Contains("FSIZE"))
{
byte[] fileCont = new byte[600];
for (int k = 400; k < 1000; k++)
fileCont[k-400] = buffer[k];
fileName = headerStr.Split(new String[] { "FNAME" }, StringSplitOptions.None)[0];
fileName = fileName.Split(new String[] { "FHEAD" }, StringSplitOptions.None).Last();
String fileSizeStr = headerStr.Split(new String[] {"FSIZE"},StringSplitOptions.None)[0];
fileSizeStr = fileSizeStr.Split(new String[] { "FNAME" }, StringSplitOptions.None).Last();
fileSize = Convert.ToUInt64(fileSizeStr);
String dirPath = Environment.GetEnvironmentVariable("USERPROFILE") + "\\documents\\conquer_client_fetches";
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
String filePath = dirPath + "\\" + fileName;
fStream = new FileStream(filePath,FileMode.Append,FileAccess.Write);
if(fileSize < 600)
{
fStream.Write(fileCont,0,(int) fileSize);
bytesRecCount = fileSize;
bytesLeft = fileSize - bytesRecCount;
}
else
{
fStream.Write(fileCont, 0, 600);
bytesRecCount = 600;
bytesLeft = fileSize - bytesRecCount;
}
}
else
{
if(bytesLeft < 1000)
{
fStream.Write(buffer,0,(int) bytesLeft);
bytesRecCount += bytesLeft;
bytesLeft = fileSize - bytesRecCount;
}else
{
fStream.Write(buffer,0,1000);
bytesRecCount += 1000;
bytesLeft = fileSize - bytesRecCount;
}
}
}
}
我得到以下异常:
System.IO.IOException: Unable to write data to the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
at System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at Conquer_server.Conquer_server.fetchThreadMethod(Object commandArgs) in C:\Users\tobb9\source\repos\Conquer_server\Conquer_server\Conquer_server.cs:line 241
-2146232800
Unable to write data to the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.