Socket.Send,服务器收到很多无效的 MPacket

Posted

技术标签:

【中文标题】Socket.Send,服务器收到很多无效的 MPacket【英文标题】:Socket.Send, server receive many invalid MPacket 【发布时间】:2014-09-10 22:53:21 【问题描述】:
[Serializable]
public class Packet : ISerializable

Packet 是我的类用于保存数据、实现 ISerializable 以及我从中读取的所有必需的构造函数和函数 [http://msdn.microsoft.com/en-us/library/ms182342.aspx]

[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
protected virtual void GetObjectData(SerializationInfo info, StreamingContext context)
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
private void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
protected Packet(SerializationInfo info, StreamingContext context)

我将我的数据包放在一个 dll 中并在服务器和客户端应用程序中引用它,以便他们可以使用 TcpListener 传输数据包(转换为 byte[] 并发送、接收和转换回)

我测试了服务器客户端与单个数据包完美配合,无需发送文件或小于或等于 1mb 文件。 这是从客户端收到带有重命名命令的数据包时的服务器日志

[7174c67d-518f-4960-affe-d3bc67320d7e] Waiting for message
20/07/2014 13:03:48: Rename SUCCESS from 7174c67d-518f-4960-affe-d3bc67320d7e to NewName

每个数据包,它把最大 1mb 长度的字节数组作为文件部分的数据放在 byte[] msgFileData 属性和 TcpListener 接收最大 2mb。

问题是在发送超过 1mb 的文件时,我将该文件拆分为每个最大 1mb 的部分,并且只有一些以正确格式接收的数据包可以反序列化,而有些数据包格式无效。 它工作了一点时间,通常会显示这个错误,所以我只能在幸运的时刻上传它

        20/07/2014 13:03:48: Rename SUCCESS from 7174c67d-518f-4960-affe-d3bc67320d7e to NewName
    20/07/2014 13:03:48: [NewName] Waiting for message
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 1/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: Uploaded 2/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: Error Packet: System.Runtime.Serialization.SerializationException: Binary stream '228' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at engine.converter.prjnameConverter.BinaryDeserializeObject[T](Byte[] serializedType) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 74
       at engine.converter.prjnameConverter.DeSerializeFromByteArray[T](Byte[] data) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 52
       at prjname.entity.Client.readResponsePacket(Byte[] data, Packet& Packet, Boolean& bValidPacket) in d:\Work\C#\Project\Work\prjname-Server\entity\Client.cs:line 154
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 3/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: Error Packet: System.Runtime.Serialization.SerializationException: The input stream is not a valid binary format. The starting contents (in bytes) are: 30-0A-00-80-B2-98-3D-A7-FC-B4-41-FC-4F-02-81-03-8A ...
       at System.Runtime.Serialization.Formatters.Binary.SerializationHeaderRecord.Read(__BinaryParser input)
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadSerializationHeaderRecord()
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at engine.converter.prjnameConverter.BinaryDeserializeObject[T](Byte[] serializedType) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 74
       at engine.converter.prjnameConverter.DeSerializeFromByteArray[T](Byte[] data) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 52
       at prjname.entity.Client.readResponsePacket(Byte[] data, Packet& Packet, Boolean& bValidPacket) in d:\Work\C#\Project\Work\prjname-Server\entity\Client.cs:line 154
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Error Packet: System.Runtime.Serialization.SerializationException: The input stream is not a valid binary format. The starting contents (in bytes) are: 2B-01-83-40-2E-12-63-8F-C7-F6-89-B2-40-8C-CC-86-2E ...
       at System.Runtime.Serialization.Formatters.Binary.SerializationHeaderRecord.Read(__BinaryParser input)
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadSerializationHeaderRecord()
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at engine.converter.prjnameConverter.BinaryDeserializeObject[T](Byte[] serializedType) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 74
       at engine.converter.prjnameConverter.DeSerializeFromByteArray[T](Byte[] data) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 52
       at prjname.entity.Client.readResponsePacket(Byte[] data, Packet& Packet, Boolean& bValidPacket) in d:\Work\C#\Project\Work\prjname-Server\entity\Client.cs:line 154
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Error Packet: System.Runtime.Serialization.SerializationException: Binary stream '57' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at engine.converter.prjnameConverter.BinaryDeserializeObject[T](Byte[] serializedType) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 74
       at engine.converter.prjnameConverter.DeSerializeFromByteArray[T](Byte[] data) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 52
       at prjname.entity.Client.readResponsePacket(Byte[] data, Packet& Packet, Boolean& bValidPacket) in d:\Work\C#\Project\Work\prjname-Server\entity\Client.cs:line 154
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Error Packet: System.Runtime.Serialization.SerializationException: The input stream is not a valid binary format. The starting contents (in bytes) are: AA-01-17-58-02-01-40-C1-D1-51-10-38-29-A8-D5-68-C0 ...
       at System.Runtime.Serialization.Formatters.Binary.SerializationHeaderRecord.Read(__BinaryParser input)
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadSerializationHeaderRecord()
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at engine.converter.prjnameConverter.BinaryDeserializeObject[T](Byte[] serializedType) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 74
       at engine.converter.prjnameConverter.DeSerializeFromByteArray[T](Byte[] data) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 52
       at prjname.entity.Client.readResponsePacket(Byte[] data, Packet& Packet, Boolean& bValidPacket) in d:\Work\C#\Project\Work\prjname-Server\entity\Client.cs:line 154
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Error Packet: System.Runtime.Serialization.SerializationException: Binary stream '150' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.
       at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at engine.converter.prjnameConverter.BinaryDeserializeObject[T](Byte[] serializedType) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 74
       at engine.converter.prjnameConverter.DeSerializeFromByteArray[T](Byte[] data) in d:\Work\C#\Project\Work\prjnameDll\converter\prjnameConverter.cs:line 52
       at prjname.entity.Client.readResponsePacket(Byte[] data, Packet& Packet, Boolean& bValidPacket) in d:\Work\C#\Project\Work\prjname-Server\entity\Client.cs:line 154
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 4/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName

一定是这样的

    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 1/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 2/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 3/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 4/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName
    20/07/2014 13:04:22: [NewName] Waiting for message
    20/07/2014 13:04:22: Uploaded 5/5 part of AMediumFile5mb.mp3 (Guid 40695b81-18b1-4329-bb00-344474458c47) from NewName

**********客户*************

MainForm.cs

private void uploadFileToServerToolStripMenuItem_Click(object sender, EventArgs e)
    
        OpenFileDialog dlgChooseUploadFile = new OpenFileDialog();
        dlgChooseUploadFile.Multiselect = false;
        /*some code*/
        if (dlgChooseUploadFile.ShowDialog() == DialogResult.OK)
        
            /*some code*/
            string strFilePath = dlgChooseUploadFile.FileName;
            muUser.Upload(strFilePath); //muUser is class User
        
    

用户.cs

    public void Upload(string strFilePath)
    
        OnLockForm(true); // Disable MainForm while uploading
        UploadingForm uploader = new UploadingForm(strFilePath, this);//=> this: pass user as parameter to get user info like name, NetworkStream for sending request
        uploader.OnStopUpload += new UploadingForm.StopUpload((string strMessage)=>
        
            OnLockForm(false);
            OnNotifyMessage(strMessage);
        );
        uploader.ShowDialog();
    

上传Form.cs

public partial class UploadingForm : Form

    public delegate void StopUpload(string strMessage);
    public StopUpload OnStopUpload;
    private string mstrFilePath;
    private User sender;
    public UploadingForm(string strFilePath, User sender)
    
        CheckForIllegalCrossThreadCalls = false;
        this.mstrFilePath = strFilePath;
        this.sender = sender;
        InitializeComponent();
    

    private void UploadingForm_Shown(object sender, EventArgs e)
    
        //some code
        ParepareUpload();
    
    private void ParepareUpload()
    
        Uploader uploader = new Uploader(mstrFilePath, sender);
        uploader.OnAPartUploaded += new Uploader.APartUploaded(()=>
        
            /*some code but I disabled this delegate*/
        );
        uploader.OnUploadCanceled+= new Uploader.UploadCancel((string strReason)=>
        
            OnStopUpload(strReason);
            this.Dispose();
        );
        uploader.OnUploadCompleted += new Uploader.UploadCompleted(() =>
        
            OnStopUpload("Upload done");
            this.Dispose();
        );
        uploader.Begin();
    

上传者.cs

public class Uploader

    public delegate void UploadCompleted();
    public UploadCompleted OnUploadCompleted;
    public delegate void APartUploaded();
    public APartUploaded OnAPartUploaded;
    public delegate void UploadCancel(string strReason);
    public UploadCancel OnUploadCanceled;

    public string mstrFilePath  get; private set; 
    public string mUserName  get; private set; 
    public Guid mGuid  get; private set; 
    private NetworkStream mnetStream  get; set; 

    public Uploader(string strFilePath, User sender)
    
        this.mGuid = Guid.NewGuid();
        this.mUserName = sender.mstrName;
        this.mstrFilePath = strFilePath;
        this.mnetStream = sender.netStream;
    

    public void Begin()
    
        /*some code*/
        BeginUploadFile();
    

    private void BeginUploadFile()
    
        try
        
            string strFileName = Path.GetFileName(mstrFilePath);
            long lFileSize = new FileInfo(mstrFilePath).Length;
            byte iPartsCount = (byte)Math.Ceiling((decimal)lFileSize / engine.data.Packet.PACKET_MAXSIZE_UPLOADPART);
            for (byte i = 1; i <= iPartsCount; i++)
            
                int numBytesToRead = Packet.PACKET_MAXSIZE_UPLOADPART;
                if (i == iPartsCount)
                
                    numBytesToRead = (int)(lFileSize - ((i - 1) * Packet.PACKET_MAXSIZE_UPLOADPART));
                
                sendPacket(Packet.CreatePFileUpload(strFileName, i, iPartsCount, readPartOfFile(Packet.PACKET_MAXSIZE_UPLOADPART * (i - 1), numBytesToRead), mGuid));
            
            OnUploadCompleted();
        
        catch (Exception ex)
        
            OnUploadCanceled(ex.ToString());
        
    

    private object sync_readPartOfFile = new object();
    private byte[] readPartOfFile(int iByteFrom, int numBytesToRead)
    
        lock (sync_readPartOfFile)
            try
            
                using (FileStream fsSource = new FileStream(mstrFilePath, FileMode.Open, FileAccess.Read))
                
                    fsSource.Seek(iByteFrom, SeekOrigin.Begin);
                    iByteFrom = 0;
                    long lEnd = fsSource.Length;
                    // Read the source file into a byte array.
                    byte[] bytes = new byte[numBytesToRead];
                    while (numBytesToRead > 0)
                    
                        // Read may return anything from iByteFrom to numBytesToRead. 
                        int n = fsSource.Read(bytes, iByteFrom, numBytesToRead);

                        // Break when the end of the file is reached. 
                        if (n == 0)
                            break;

                        iByteFrom += n;
                        numBytesToRead -= n;
                    
                    return bytes;
                
            
            catch
            
                throw;
            
    

    private object sync_sendRequest = new object();
    private void sendPacket(Packet request)
    
        lock (sync_sendRequest)
            try
            
                request.pkOwner = mUserName;
                byte[] buffer = weHereConverter.SerizableObject(request);
                mnetStream.Write(buffer, 0, buffer.Length);
                mnetStream.Flush();
                //OnAPartUploaded(); /*tempolary disabled*/
            
            catch (Exception)
            
                throw;
            
    

********服务器************

ClientManager.cs // 保存客户端列表

    public void Listen(TcpClient tcpClient, string strName)
    
        Client client = new Client(tcpClient, strName);
        client.OnNotifyDisconnect += new Client.NotifyDisconnect(ClientDisconnect);
        client.OnNotifyMessage += new Client.NotifyMessage(ClientMessage);
        client.OnNotifyReceivedData += new Client.NotifyReceivedData(ClientReceivedData);
        lock (sync_mlistClient)
        
            Packet pkNotifySignIn = Packet.CreatePServerNotify("*ding* welcome...someone");
            foreach (Client c in mlistClient)
            
                try
                
                    c.send(pkNotifySignIn);
                
                catch  
            
            mlistClient.Add(client);
        
        client.BeginListen();
    

    private void ClientReceivedData(Packet pkData, Client client)
    
        if (pkData.isSCmd())
        
            if (pkData.ScmdType == Command.SCMD_RENAME) // packet rename
            
                /*some code*/
            
            else if (pkData.ScmdType == Command.SCMD_FILEUPLOAD)
            
                //new Thread(() => thread_UploadFile(pkData)).Start();
                thread_UploadFile(pkData);
            
            else
            
                /*some code*/
            
        
        else if (pkData.isMessage())
        
            new Thread(() => ForwardMessageToClient(pkData, client)).Start();
        
        else
        
            /*some code*/
        
    

    // named thread but I call it like a normal method
    private void thread_UploadFile(Packet pkUploadData)
    
        //new Thread(() => thread_OnUploadingFile(pkUploadData)).Start();
        thread_OnUploadingFile(pkUploadData);
    

    private object sync_thread_OnUploadingFile = new object();
    private void thread_OnUploadingFile(Packet pkUploadData)
    
        lock (sync_thread_OnUploadingFile)
        
            FileUploadInfo uploadInfo = getFileUploadInfo(pkUploadData);
            if (uploadInfo.Fail) // reject packet, Fail marked as true when exception occured while writing to server's hard disk
                return;
            try
            
                File.WriteAllBytes(getUploadFilePart(pkUploadData.ScmdFileUploadGuid, pkUploadData.ScmdFileUploadPartNumber), pkUploadData.msgFileData);
            
            catch (Exception ex)
            
                /*server log*/MakeThreadNotifyMessage("Error while uploading part " + pkUploadData.ScmdFileUploadPartNumber + "/" + pkUploadData.ScmdFileUploadPartsCount + " of " + pkUploadData.ScmdFileUploadName + " (Guid " + pkUploadData.ScmdFileUploadGuid + ") from " + pkUploadData.pkOwner + "\r\n" + ex);
                uploadInfo.Fail = true;
            
            finally
            
                uploadInfo.OnAPartUploaded(); // increase count part uploaded in uploadInfo
                if (!uploadInfo.Complete)
                    /*server log*/MakeThreadNotifyMessage("Uploaded " + uploadInfo.CountPartsUploaded + "/" + pkUploadData.ScmdFileUploadPartsCount + " part of " + pkUploadData.ScmdFileUploadName + " (Guid " + pkUploadData.ScmdFileUploadGuid + ") from " + pkUploadData.pkOwner);
            
        
    

    private Dictionary<Guid, FileUploadInfo> mdictFileUpload = new Dictionary<Guid, FileUploadInfo>();
    private object sync_mdictFileUpload = new object();
    private FileUploadInfo getFileUploadInfo(Packet pkUploadData)
    
        lock (sync_mdictFileUpload)
        
            FileUploadInfo result;
            if (!mdictFileUpload.TryGetValue(pkUploadData.ScmdFileUploadGuid, out result))
            
                mdictFileUpload.Add(pkUploadData.ScmdFileUploadGuid, result = new FileUploadInfo(
                        pkUploadData.pkOwner, // uploader's name
                        pkUploadData.ScmdFileUploadGuid, // file guid because I save on save like G-U-I-D-filename_partposition.part
                        pkUploadData.ScmdFileUploadName,  // file name
                        pkUploadData.ScmdFileUploadPartsCount // total parts count, ex: 5mb file will be splited into 5 parts
                        ));
                result.OnFileUploadCompleted += new FileUploadInfo.NotifyFileUploadCompleted(UploadCompleted);
            
            return result;
        
    

文件上传信息.cs

    public class FileUploadInfo

    public delegate void NotifyFileUploadCompleted(FileUploadInfo uploadFile);
    public NotifyFileUploadCompleted OnFileUploadCompleted;
    public string UploaderName  get; private set; 
    public string FileName  get; private set; 
    public int PartsCount   get; private set; 
    public Guid FileUploadGuid  get; private set; 
    private int _CountPartsUploaded = 0;
    private object sync_CountPartsUploaded = new object();
    public int CountPartsUploaded
    
        private set
        
            lock (sync_CountPartsUploaded)
                _CountPartsUploaded = value;
        
        get
        
            lock (sync_CountPartsUploaded)
                return _CountPartsUploaded;
        
    
    private bool _Fail = false;
    private object sync_Fail = new object();
    public bool Fail
    
        get
        
            lock (sync_Fail)
                return _Fail;
        
        set
        
            lock (sync_Fail)
                _Fail = value;
        
    
    private bool _Complete = false;
    private object sync_Complete = new object();
    public bool Complete
    
        get
        
            lock (sync_Complete)
                return _Complete;
        
        set
        
            lock (sync_Complete)
                _Complete = value;
        
    

    public FileUploadInfo(string UploaderName, Guid FileUploadGuid, string FileName, int PartsCount)
    
        this.UploaderName = UploaderName;
        this.FileUploadGuid = FileUploadGuid;
        this.FileName = FileName;
        this.PartsCount = PartsCount;
    

    public void OnAPartUploaded()
    
        CountPartsUploaded += 1;
        if (CountPartsUploaded >= PartsCount)
        
            OnFileUploadCompleted(this);
            Complete = true;
        
    

客户端.cs

        byte[] message = new byte[2097152];
        int bytesRead;
        while (true)
        
            bytesRead = 0;
            #region read client SPacket
            try
            
                //blocks until a client sends a message
                /*server log*/OnNotifyMessage("[" + mstrName + "] Waiting for message");
                bytesRead = netStream.Read(message, 0, 2097152);
                if (bytesRead == 0)
                
                    //the client has disconnected from the server
                    break;
                
            
            catch (Exception ex)
            
                notifyError("Socket error", ex);
                break;
            
            #endregion

            //message has successfully been received
            Packet pkRequestFromClient;
            Boolean bValidPacket;
            readRPacket(message, out pkRequestFromClient, out bValidPacket);
            if (bValidPacket)
            
                processRequestPacket(pkRequestFromClient);
            
            else
            
                /*server log*/OnNotifyMessage("Error packet: "+ pkRequestFromClient.Exception);
            

    private void readRPacket(byte[] data, out Packet packet, out bool bValidPacket)
    
        try
        
            packet = weHereConverter.DeSerializeFromByteArray<Packet>(data);
            bValidPacket = true;
        
        catch(Exception ex)
        
            packet = Packet.CreateErrorPacket(ex);
            bValidPacket = false;
        
    

真的需要帮助..

感谢阅读!

【问题讨论】:

向我们展示客户端(拆分代码)和服务器端(合并代码) 我认为是因为线程,是吗? @Alireza 是的,请看一下 @Elahe 我删除了线程但还是一样 我仍然看不到您将文件分成 1MB 的部分 【参考方案1】:

行后

bytesRead = netStream.Read(message, 0, 2097152);

您没有使用bytesRead 来确定接收了多少字节。您假设收到了整条消息。 TCP 为您提供字节流,它不会以任何方式保留消息。即使 Read 决定始终只读取一个字节,您的代码也必须正常运行。


您的代码中有很多传输逻辑。上传是不是不能使用标准化的协议,比如HTTP、FTP、WebServices、protobuf?套接字代码很难正确。最好的方法是避免它。

【讨论】:

“您没有使用 bytesRead 来确定接收了多少字节。您假设收到了整条消息”好吧,我知道了。在我的问题中,数据包是否一次发送但并非所有数据都到达服务器,那么如果它接收到我的数据包的所有数据我该怎么办? “难道不能使用标准化的协议进行上传,比如HTTP、FTP、WebServices、protobuf?”不,我想学习如何将套接字与产品一起使用,以供我将来的团队合作:D 你的问题对我来说有点不清楚。您需要以某种方式确保仅将整个数据包传递给反序列化代码。如果您使用 protobuf 作为有线格式,您只需将 NetworkStream 传递给 protobuf,一切都会得到处理。如果您坚持手动添加长度前缀。【参考方案2】:

这是一个竞争条件。

问题是当您发送(例如)一个 1.2MB 的文件时,有可能在第一个 1MB 部分之前处理第二个 0.2MB 部分并将其写入文件。

因此,您可以在客户端和服务器端同步执行所有操作,或者(我推荐这样做)在服务器端对数据包进行排队,按索引升序排列它们,然后以正确的顺序写入它们。

如果您在实施方面需要帮助,请告诉我

【讨论】:

我不完全理解你的答案,但我会改为排队。客户端(C) -> 文件信息 -> 服务器 (S) S -> 请求第 1 部分 -> CC -> 发送第 1 部分 -> S /*loop*/ 非常感谢 ^^ 我想投票,但它需要 15声誉。 我对结果很好奇。请随时通知我,不要介意投票。问题解决后,您可以将我的答案标记为正确答案:) 是的,我会仔细验证并给你结果。反正我不能再相信 TCP 了:)) 现在我要做jsf作业,结果会在1或2天后发布 TCP在这里是无罪的。我会正确地交付您的每个数据包。但它不会让较小的数据包等待较大的数据包,因为它不知道它们是相关的。这应该在您的代码中实现:)

以上是关于Socket.Send,服务器收到很多无效的 MPacket的主要内容,如果未能解决你的问题,请参考以下文章

套接字:send() 函数返回“Broken Pipe”错误

Socket send函数和recv函数详解

Socket send函数和recv函数详解

socket.send 在 io.sockets.on() 之外

websock使用

socket通信的流程