如题:用udp在局域网进行广播来发送文件.大家来讨论一下菌体的实现方法

解决方案 »

  1.   

    1.首先自定义一个数据包头 
      Struct SendData
      {
         uint8 nType; //数据包,应答包?
         int Seq;
        char* data(){(char*)(this+1)}
      }
    2.将文件分成若干块,在每块数据中加上包头,然后按顺序组播发送。
    3.发送端为每一个组播对象维护一个链表。用于记录每个组播对象收到(或没收到)的数据包
    4.接收端在收到每个数据包之后向发送端发送一个应答数据哦·,表示该数据包已收到。
    5.发送端在数据发送完毕之后,遍历每个组播对象的链表,重发组播对象没有接受到的数据包
      

  2.   

    http://topic.csdn.net/u/20100712/22/c4b467fd-e3d3-48c8-8deb-d89f19430ea0.htmlLZ去看看有没有你需要的~
      

  3.   

    额 自己看看 完整的代码/**************************************************************  
    *接收线程的回调函数  
    *发送的数据块结构解析:  
    *类别 字节号     内容  
    *H      1           通信头,申请发送  
    *H      2~257       文件名  
    *H      258~...     文件大小  
    *D      1           通信头,拒绝接收  
    *R      1           通信头,同意接收  
    *F      1           通信头,发送文件块  
    *F      2~17        保留  
    *F      18~...      文件数据块  
    *E      1           通信头,文件尾发送  
    *E      2~17        块大小  
    *E      18~...      文件数据块  
    **************************************************************/ 
    DWORD WINAPI CT42udpDlg::RecvProc(LPVOID lpParameter)//这个就是接收客户端请求的线程 
    {
    SOCKET sock=((RECVPARAM*)lpParameter)->sock;
    HWND hWnd=((RECVPARAM*)lpParameter)->hWnd;
    delete lpParameter;
        //保存客户端地址 
    SOCKADDR_IN addrFrom;
    int len=sizeof(SOCKADDR);
    char recvBuf[0x412]; //256*4+17字节的缓冲
    char fileName[0x400];       //256字节的文件名存储区
    int retval, i;
    FILE* file = NULL;
        //等待客户端请求到来
    while(TRUE)
    {
    //接受UDP数据   
    retval=recvfrom(sock,recvBuf,0x412,0,(SOCKADDR*)&addrFrom,&len);

    if(SOCKET_ERROR == retval)
    break;
            //收到消息头为'R',即对方同意让你继续发送数据   
    if (recvBuf[0] == 'R')
    {
    char wParam = 'R';
    //将要显示的信息用另外一个函数来实现,因为这个线程函数是静态的!
    //WM_READY_TO_RECEIVE用户自定义的消息
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, 0);
    }
            //收到消息头为'D',即对方拒绝让你继续发送数据 
    else if (recvBuf[0] == 'D')
    {
    char wParam = 'D';
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, 0);
    }
            //收到消息头为'H',即对方申请给你发送信息,并送来文件的信息
    else if (recvBuf[0] == 'H')
    {
    //从收到的数据中提取文件名信息
    for (i = 1; i <= 0x400 && recvBuf[i] != '\0'; i++) //前256字节用于存储文件名
    fileName[i-1] = recvBuf[i];
    fileName[i-1] = '\0';
    //从收到的数据中提取文件大小信息
    CString recvMsg;
    nFileSize = atoi(&recvBuf[0x401]);
    recvMsg.Format("收到来自于(%s)的文件:%s\n文件大小:%i字节\n是否接收?",
    inet_ntoa(addrFrom.sin_addr), fileName, nFileSize);
     //用消息框提示用户有人要发送文件
    if (IDOK == AfxMessageBox(recvMsg, MB_OKCANCEL))
    {
    //若用户同意接收,提供一个文件保存对话框用于设定保存的路径 
    CFileDialog saveDlg(false, NULL, fileName);

    if (IDOK == saveDlg.DoModal())
    {
    //创建一个文件用于复制接收的文件数据 
    if (!(file = fopen(saveDlg.GetPathName(), "wb")))
    {
    AfxMessageBox("创建本地文件失败!");
    continue;
    }
    /* int tem=file.GetLength();
    CString  strtem;
    strtem.Format(_T("%i"),tem);
    MessageBox(strtem);*/
    char wParam = 'H';
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, (LPARAM)&addrFrom);
    }
    else
    {
    char wParam = 'C';
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, (LPARAM)&addrFrom);
    }
    }
    else//用户拒绝接收   
    {
    char wParam = 'C';
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, (LPARAM)&addrFrom);
    } }
     //收到的消息头为'F',即对方发来的是文件数据 
    else if (recvBuf[0] == 'F')
    {
    //将文件数据写入本地文件中 
    fwrite(&recvBuf[0x12], 1, 0x400, file);
    char wParam = 'F';
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, (LPARAM)&addrFrom);
    }
    //收到的消息头为'E',即对方发来最后一个数据块  
    else if (recvBuf[0] == 'E')
    {
    //获取数据块的大小  
    int bufSize = atoi(&recvBuf[1]);
    //将数据块写入本地文件,并关闭文件  
    fwrite(&recvBuf[0x12], 1, bufSize, file);
    fclose(file);
    char wParam = 'E';
    ::PostMessage(hWnd, WM_READY_TO_RECEIVE, (WPARAM)&wParam, (LPARAM)&addrFrom);
    }
    //收到未定义的数据头
    else
    AfxMessageBox("传送数据过程中出现错误!");
    }
    return (DWORD)NULL;
    }void CT42udpDlg::OnQuit() 
    {
    OnCancel();
    }
    /*************************************************************  
    *按下发送键,发出文件信息的函数  
    *************************************************************/  
    void CT42udpDlg::OnSend() 
    {
    CFileDialog openFile(true);
    if (IDOK == openFile.DoModal())
    {
    m_filePath = openFile.GetPathName();
    UpdateData(false);
    }
    if (m_posting)
    {
    MessageBox("数据发送中,请稍候再试。");
    return;
    } UpdateData(); if (m_filePath == "")
    {
    MessageBox("请输入要发送的文件路径!");
    return;
    }

    if (m_oIP.IsBlank())
    {
    MessageBox("请添入接收者的IP地址。");
    return;
    } WIN32_FIND_DATA FindFileData; if (INVALID_HANDLE_VALUE == FindFirstFile(m_filePath, &FindFileData))
    {
    MessageBox("文件路径错误或文件不存在!\n请重新指定文件路径。");
    return;
    } DWORD dwIP;
    m_oIP.GetAddress(dwIP); SOCKADDR_IN addrTo;
    addrTo.sin_family=AF_INET;
    addrTo.sin_port=htons(4660);
    addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
        //构建文件信息数据块  
    char sendBuf[0x412];
    int i;
        //消息头   
    sendBuf[0] = 'H';
        //文件名 
    for (i = 1; i <= 0x400 && FindFileData.cFileName[i-1] != '\0'; i++)
    sendBuf[i] = FindFileData.cFileName[i-1];
    sendBuf[i] = '\0';
        //文件大小   
    _itoa(FindFileData.nFileSizeLow, &sendBuf[0x401], 10);
    sendBuf[0x411] = '\0';
        //发送数据块  
    sendto(m_socket, sendBuf, 0x412, 0,
    (SOCKADDR*)&addrTo, sizeof(SOCKADDR));
        //打开文件,等待读取
    if (!(m_file = fopen(m_filePath, "rb")))
    {
    MessageBox("读取文件失败!");
    }
    m_nSend = 0;//已发送的块数
    m_nFileSize_s = FindFileData.nFileSizeLow;//文件大小 
    m_progress.SetRange(0, 100);//设置发送进度条
    m_posting = true;//标明发送正进行}
    /************************************************************  
    *消息响应函数  
    *响应自定义消息WM_READY_TO_RECEIVE  
    ************************************************************/  
    void CT42udpDlg::OnReadyToRecv(WPARAM wParam,LPARAM lParam)
    {
    char sendBuf[0x412];
    DWORD dwIP;
    m_oIP.GetAddress(dwIP); SOCKADDR_IN addrTo;
    addrTo.sin_family=AF_INET;
    addrTo.sin_port=htons(4660);
    addrTo.sin_addr.S_un.S_addr=htonl(dwIP); int nRead; switch (*(char*)wParam)
    {
        //对方拒绝接收文件,关闭已打开的文件  
    case 'D':
    MessageBox("对方拒绝接受你发送的文件!");
    fclose(m_file);
    m_posting = false;
    break;
    //对方同意接收文件 
    case 'R':
    nRead = fread(&sendBuf[0x12], 1, 0x400, m_file);
        //读取的文件小于256*4字节,则读到文件尾 
    if (nRead < 0x400)
    {
    sendBuf[0] = 'E';
    _itoa(nRead, &sendBuf[1], 10);
    sendto(m_socket, sendBuf, nRead+0x12, 0,
    (SOCKADDR*)&addrTo, sizeof(SOCKADDR));
    fclose(m_file);
    m_progress.SetPos(100);
    m_posting = false;
    UpdateData(false);
    MessageBox("发送完毕!");
    m_progress.SetPos(0);
    UpdateData(false);
    }
    //读到文件等于256字节,则文件还未读完  
    else
    {
    sendBuf[0] = 'F';
    sendto(m_socket, sendBuf, 0x412, 0,
    (SOCKADDR*)&addrTo, sizeof(SOCKADDR)); m_nSend++;
    m_progress.SetPos((int)((float)m_nSend/(m_nFileSize_s/0x400+1)*100));
    UpdateData(false);
    }
    break;
    //同意接收对方文件
    case 'H':
    m_progress_r.SetRange(0, 100);//设置滚动条最小最大值
    m_nRecv = 0;
    case 'F':
    sendto(m_socket, "R", 2, 0,
    (SOCKADDR*)lParam, sizeof(SOCKADDR)); m_nRecv++;
    m_progress_r.SetPos((int)((float)m_nRecv/(nFileSize/0x400+1)*100));
    UpdateData(false);
    break;
    case 'E':
    m_progress_r.SetPos(100);
    UpdateData(false);
    MessageBox("接收完毕!");
    m_progress_r.SetPos(0);
    UpdateData(false);
    break;
    //拒绝接收,通知对方
    case 'C':
    sendto(m_socket, "D", 2, 0,
    (SOCKADDR*)lParam, sizeof(SOCKADDR));
    break;
    }
    }
      

  4.   


    假如我一次读取1024,但是发送的时候不一定发的完,我无法知道,本次发送了多少数据
    struct SendData
    {
    ULONG DataSize;
    char DataData[1024];
    };
    m_uLongLen=sizeof(ULONG);
    BufLen=sizeof(SendData);
    SendData SendBuf;
    while (1)
    {
    memset(&SendBuf,0,m_BufLen);
    len=file.Read(SendBuf.DataData,1024);
                    if (len<=0) break;
    SendBuf.DataSize=len;
    len=len+m_uLongLen;
    sendlen=sendto(sock,(char*)&SendBuf,len,0,(SOCKADDR*) &addrFileSend,sizeof(SOCKADDR));
    while (sendlen<len)
    {
    len=len-sendlen;
    sendlen=sendto(sock,(char*)&SendBuf+sendlen,len,0,(SOCKADDR*)&addrFileSend,sizeof(SOCKADDR));
    }  }
    那对方接受的时候会不会把这这一次发送的数据接受了,好多次呢?