C# tcpclient读取的字节数少于预期

C# tcpclient读取的字节数少于预期,c#,byte,tcpclient,networkstream,C#,Byte,Tcpclient,Networkstream,我的tcpclient有问题,我需要发送一个或多个文件,因此我有一个带有服务器和客户端的应用程序,协议如下: 1) 我通过streamwriter.writeline(通过函数从服务器接收)发送一些字符串,其中包含有关文件数量、文件名及其大小的信息 streamreader.readline) 2) 在这些字符串之后,我发送文件,在每个文件之后,服务器使用streamwriter.writeline“ACK”向客户机应答。该文件随 networkstream.write方法,并通过network

我的tcpclient有问题,我需要发送一个或多个文件,因此我有一个带有服务器和客户端的应用程序,协议如下:

1) 我通过streamwriter.writeline(通过函数从服务器接收)发送一些字符串,其中包含有关文件数量、文件名及其大小的信息 streamreader.readline)

2) 在这些字符串之后,我发送文件,在每个文件之后,服务器使用streamwriter.writeline“ACK”向客户机应答。该文件随 networkstream.write方法,并通过networkstream.read接收

问题是服务器一直读取,直到收到的字节等于文件大小,但是。。。尽管客户端“似乎”发送文件的每个字节,但服务器 接收的字节总数更少!因此,应用程序在此步骤中被阻止,服务器正在等待下一个字节,客户端正在等待“ACK”字符串 在发送下一个文件或仅完成操作之前使用streamreader.readline

我还想检查服务器接收到什么,所以我打印了读取周期中接收到的字节数,发现有时服务器读取的字节数少于流的缓冲区大小(固定为1024)。这应该是正常的,因为TCP会尽快读取,这不应该是真正的问题,对吗?我不能 相信tcp会丢失字节,但我不知道如何解决

在这里您可以找到部分代码:

----服务器端----------

----服务器端结束--------------

--------客户端--------------

…做一些事情。。。。
//sw是streamWriter,Sr是streamReader,stream是networkstream
System.Collections.Specialized.StringCollection formats=剪贴板.GetFileDropList();
sw.WriteLine(“客户端:文件:“+formats.Count+”*”);
sw.Flush();
//发送到服务器的文件名和相对大小
foreach(格式为字符串文件名)
{
//好吧,我的协议有道理……忽略它。
sw.WriteLine((Directory.Exists(filename))?System.IO.Path.GetFileName(filename)+“*”:System.IO.Path.GetFileName(filename));
sw.Flush();
FileStream Fs=newfilestream(文件名,FileMode.Open,FileAccess.Read);
软件写入线(Fs长度);
sw.Flush();
stream.Flush();
Fs.Close();
}
//发送文件
foreach(格式为字符串文件名)
{    
//client_sync是包装TcpClient套接字的类
客户端同步。发送单个文件(流、文件名);
resp=sr.ReadLine();
}
…正在做一些事情并结束此功能。。。
发送文件功能的定义如下:
(注意:我几周前从代码项目中获取了此函数)
public void发送单文件(NetworkStream netstream,字符串文件名)
{
//连接是我班的一个参数
如果(!已连接)返回;
字节[]SendingBuffer=null;
尝试
{
FileStream Fs=newfilestream(文件名,FileMode.Open,FileAccess.Read);
int NoOfPackets=Convert.ToInt32(数学上限(Convert.ToDouble(Fs.Length)/Convert.ToDouble(this.BufferSize));
//注意:缓冲区大小为1024
int TotalLength=(int)Fs.Length,CurrentPacketLength=0;
int bytes_send=0;
for(int i=0;i此.BufferSize)
{
CurrentPacketLength=此.BufferSize;
TotalLength=TotalLength-当前包装长度;
}
其他的
CurrentPacketLength=总长度;
SendingBuffer=新字节[CurrentPacketLength];
Fs.Read(发送缓冲区,0,CurrentPacketLength);
netstream.Write(SendingBuffer,0,SendingBuffer.Length);
字节\u发送+=当前包长度;
}
Fs.Close();
}
捕获(例外情况除外)
{
netstream.Close();
//我的职能
关闭_连接();
}
netstream.Flush();
}
---------客户端结束------


所以…有人能帮我逃离这个地狱???THX:)

简短版本:您可能不应该将文本阅读器/写入器与流混合使用。StreamReader类缓冲数据,并且可能正在获取一些用于传输二进制部分的字节。您可以自己处理文本解码,这样您就可以控制缓冲,或者使用FTP之类的控制通道设计(其中一个连接以文本形式交换命令,另一个通道以交换二进制数据)。好的,谢谢!我试图消除StreamWriter或StreamReader的每个实例,只使用NetworkStream进行通信。它很有效!
..........Doing Stuffs.............
//secServer is the TCPListener socket.
this.secSHandler = secServer.AcceptTcpClient();
this.secSHandler.ReceiveBufferSize = 1024;
this.secSHandler.SendBufferSize = 1024;

this.is_connected_now = true;

print("is connected!!! ");

//Taking streams...
this.stream = this.secSHandler.GetStream();
this.sr = new StreamReader(stream);
this.sw = new StreamWriter(stream);

string first = sr.ReadLine();
print("I read + " + first + " .");
int numFiles = 0;
string connType = first.Substring(0, 6);
    if (connType.CompareTo("CLIENT") == 0)
    {
    //SINCR CLIENT -> SERVER
    string clipType = first.Substring(7, 4);
        if (clipType.CompareTo("FILE") == 0)
        {
        //CASE RECEIVE FILE

        int posSeparator = first.IndexOf('*');
        string nFiles = first.Substring(12, first.Length - 13);
        numFiles = Convert.ToInt16(nFiles);
        string[] fileNames = new string[numFiles];
        int[] fileSizes = new int[numFiles];

            //TAKE FROM THE CLIENT ALL FILE NAMES AND SIZES
            for (int i = 0; i < numFiles; i++)
            {
            fileNames[i] = sr.ReadLine();
            print("Name file : I read " + fileNames[i]);
            string dim = sr.ReadLine();
            fileSizes[i] = Convert.ToInt32(dim);
            print("Size file : I read " + fileSizes[i]);
            }

            //RECEVING FILES
            for (int i = 0; i < numFiles; i++)
            {
            receive_single_file_1(stream, fileSizes[i], fileNames[i]); //CANNOT GO AFTER THIS POINT
            sw.WriteLine("File sent - number " + i);    
            sw.Flush();
            }
        }
    }   
.............Doing others stuffs.............

sr.Close();
sw.Close();
public bool receive_single_file_1(NetworkStream netstream, int size, string filename)
{

    int sizeToRead = 0;


    string f_name = "";
    //...f_name is the result of another operation, for the sake of the example i write only the final instruction
    f_name = filename;

    byte[] RecData = new byte[1024];
    int RecBytes = 0;

    try
    {

        int totalrecbytes = 0;
        FileStream Fs = new FileStream((tempFold + f_name), FileMode.OpenOrCreate, FileAccess.Write);
        //COUNTER OF THE WHILE
        int nciclo = 0;
        while ((RecBytes = netstream.Read(RecData, 0, 1024)) > 0)
        {
        //I defined print in another context...
        totalrecbytes += RecBytes;
        if(RecBytes!=1024)
        print("Cycle : "+ nciclo +" Content RecBytes : " + RecBytes + " e RecData.Length : " + RecData.Length + " byte reads : " + totalrecbytes + ".");

        Fs.Write(RecData, 0, RecBytes);

        if (totalrecbytes >= size)
        {
            print("Read all bytes " + totalrecbytes + " over " + size + " .");
            break;
        }

        //Refresh the buffer
        RecData = new byte[1024];

        nciclo++;
        }

print("End of transfer. Received " + totalrecbytes + "File :" + filename + " Saved on " + tempFold);
Fs.Close();


}
catch (Exception ex)
{
//Ok here i return false, but i do some other stuff before
return false;
}

return true;
}
.....DOING STUFFS....
//sw is the streamWriter, Sr the streamReader and the stream is the networkstream

System.Collections.Specialized.StringCollection formats = Clipboard.GetFileDropList();
sw.WriteLine("CLIENT:FILE:" + formats.Count + "*");
sw.Flush();
   //Sending to the server filename and relative size
   foreach (string filename in formats)
    {
      //Ok the * has sense in my protocol...ignore it.
      sw.WriteLine((Directory.Exists(filename)) ? System.IO.Path.GetFileName(filename) + "*" : System.IO.Path.GetFileName(filename));
      sw.Flush();
      FileStream Fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
      sw.WriteLine(Fs.Length);
      sw.Flush();
      stream.Flush();
      Fs.Close();
     }
     //Sending files     
     foreach (string filename in formats)
     {    
    //client_sync is the class that wrap the TcpClient socket
        client_sync.send_single_file(stream, filename);
        resp = sr.ReadLine();                
     }
....DOING STUFF AND end of this function...

The send file function is defined in this way :
(note : i take this function from code project some weeks ago)
public void send_single_file(NetworkStream netstream, string filename)
        {
        //connected is a param of my class
            if (!connected) return;
            byte[] SendingBuffer = null;
            try
            {

                FileStream Fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
                int NoOfPackets = Convert.ToInt32(Math.Ceiling(Convert.ToDouble(Fs.Length) / Convert.ToDouble(this.BufferSize)));
        //NOTE: BUFFERSIZE IS 1024
                int TotalLength = (int)Fs.Length, CurrentPacketLength = 0;
                int bytes_send = 0;

                for (int i = 0; i < NoOfPackets; i++)
                {
                    if (TotalLength > this.BufferSize)
                    {
                        CurrentPacketLength = this.BufferSize;
                        TotalLength = TotalLength - CurrentPacketLength;
                    }
                    else
                        CurrentPacketLength = TotalLength;

                    SendingBuffer = new byte[CurrentPacketLength];
                    Fs.Read(SendingBuffer, 0, CurrentPacketLength);
                    netstream.Write(SendingBuffer, 0, SendingBuffer.Length);
                    bytes_send += CurrentPacketLength;

                }
                Fs.Close();

            }
            catch (Exception ex)
            {
                netstream.Close();
                //my function
                close_connection();
            }
            netstream.Flush();

        }