socket文件接收流程

一、socket接收数据操作

1、接收数据包类型

  //文本和文件
  enum DataPackage {DP_TEXT, DP_FILE};

2、数据发送命令

   //开始发送,发送过程中, 结束发送, 接受文件发送,拒绝接收文件,取消文件发送或接收
    enum SendCmd {SC_BEGIN, SC_SENDING, SC_END, SC_ACCEPT, SC_DENY, SC_CANCEL};

3、对方对发送文件的回答,接收,拒绝和取消(发送过程中)
     enum RequestType {RT_ACCEPT, RT_DENY, RT_CANCEL, RT_UNKNOWN};
4  定义数据包结构,在文件开始发送时,数据缓冲区中前128个字节用于存储文件名,其后是文件数据,而在文件发送过程中,

数据缓冲区中均是文件数据

5、数据包结构体 CDataPakage

class  CDataPackage
{
public:
    DataPackage    m_Type;                         //数据包类型
    SendCmd        m_Cmd;                       //文件发送命令
    DWORD          m_dwSize;                     //数据报结构大小
    DWORD          m_dwFileSize;                 //整个文件大小
    DWORD          m_dwData;                    //m_Data的大小
    BYTE          m_Data[];                      //数据缓冲区
};

6、定义变量值
    CClientSock   m_ClientSock;            //定义本地套接字
    HGLOBAL          m_hGlobal;                //全局堆句柄
    BOOL                m_bSending;                //文件是否处于发送过程中

7、文件接收流程、步骤

(1)、自定义设置一次接收文件大小nMaxLen、全局缓存变量hGlobal、接收缓冲区变量指针pBuffer、实际接收大小nFact、

   以及数据包是否完整bCompleted和是否第一次标记bFirstRec

(2)、计算数据包的大小 nPackage

(3)、如果是第一次接收,认为数据包中一定包含完整的数据包结构信息,数据不一定完整

  获取缓冲区数据(pBuffer):

  3.1、如果实际接收大小正好是一个数据包的大小,直接写入文件,标记本次完成bCompleted=true,下一次(bFirstRec=true)

  ,进行下一次接收(步骤三)

    nFact - nPackage(包结构大小) < CDataPackage->m_dwData

  3.2、数据包不完整,可能大于一个数据包也可能小于一个数据包

    3.2.1、当小于数据包大小(数据包中没有包含完整的数据,产生了分包)nFact - nPackage(包结构大小)< CDataPackage->m_dwData

      将数据存入全局变量hGlobal,合并到下一次数据中,此时设置bFirstRec = FALSE

    3.2.2、当大于数据包大小 (数据包中包含不止一个数据包,产生了粘包)

      先写入一个数据包到文件,在计算剩余数据包的大小nLeaving,循环nLeaving:

      3.2.2.1 nLeaving > nPackage数据包含有完整的数据包结构(即可以获取数据包的其他信息nPackage(包结构大小))

            如果数据中包含一个或一个以上的数据包,直接写入数据包到文件,nLeaving-=nPackage+CDataPackage->m_dwData;

            如果剩余数据小于一个数据包,操作和 3.2.1步骤相同,此时bCompleted = FALSE; bFirstRec = FALSE;

      3.2.2.1 nLeaving < nPackage  步骤和3.2.1相同此时nLeaving = 0; bCompleted = FALSE;

 (4)、如果是第不是第一次接收

  4.1、如果之前接收的数据包是完整的(bCompleted=true)时,返回到步骤(3)

    4.2、如果之前的数据包产生了分包或粘包(bCompleted == FALSE),继续接收数据

      4.2.1将全局变量hGlobal值取出到dwSize:

         4.2.1.1、dwSize<nPackage(如果数据包结构不完整,先接收数据包的结构),将这次实际接收值nFact与dwSize求和与nPackage比较,

         4.2.1.1.1、dwSize + nFact < nPackage(当前的数据添加到堆中仍不能描述完整的数据包结构),将dwSize + nFact字节大小数据值

               放入全局变量hGlobal操作和 3.2.1步骤相同,此时bCompleted = FALSE; bFirstRec = FALSE;返回

         4.2.1.1.2  dwSize + nFact>nPackage当前的数据添加到堆中能够描述完整的数据包结构

              先填充数据包结构,从nFact中取出数据nNeedPackage=nPackage-dwSize,在拼装成一个完整的数据包结构,

          这样可以通过完整的包结构取出这次接收到的数据大小和数据:

              如果nFact-nNeedPackage<CDataPackage->m_dwData(pBuffer中包含的数据不是一个完整的数据包数据),

          将dwSize + nFact字节大小放入全局变量hGlobal

              如果nFact-nNeedPackage>CDataPackage->m_dwData(pBuffer中包含了完整的数据包数据,并且可能包含

          多个数据包),将dwSize字节的数据和CDataPackage->m_dwData放入同一个数据包,将数据包写入到文件,执行步骤和3.2.2相同

      4.2.1.2、dwSize >= nPackage数据包结构完整,接收数据,将dwSize大小字节,拼装成一个完整的数据包结构,

          这样可以通过完整的包结构取出这次接收到的数据大小和数据:

        4.2.1.2.1、dwSize + nFact >= CDataPackage->m_dwData+nPackage(如果之前接收的数据与现在接收的数据能够

            构成至少一个完整的数据包),将dwSize字节的数据和CDataPackage->m_dwData+nPackage-dwSize放入同

          一个数据包,将数据包写入到文件,接下来执行步骤和3.2.2相同

        4.2.1.2.2、接收的数据与现在接收的数据不能构成一个完整的数据包,还需要继续接收数据,将dwSize + nFact字节大小

          放入全局变量hGlobal

  4.3、继续执行接收操作,后来步骤和以上相同

8、写文件操作

  8.1、m_Cmd =SC_BEGIN开始发送如果第一次写,读取文件名,创建文件,即开头的128个字节是文件名,

      将后面的(除128个字节外的数据写入文件), 发送接收标记;

      如果此时点击取消文件接收,想客户端发送取消标记

  8.2、如果文件时文件发送中,则继续写文件

  8.3、m_Cmd =SC_END  设置结束标记  m_bSending = FALSE;   

  8.4、m_Cmd = SC_CANCEL对方取消了文件发送

 

posted @ 2015-06-07 02:18  junxing  阅读(846)  评论(0)    收藏  举报