急!!!!高手帮我支个招:用udp广播发送文件 如题:用udp在局域网进行广播来发送文件.大家来讨论一下菌体的实现方法 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 1.首先自定义一个数据包头 Struct SendData { uint8 nType; //数据包,应答包? int Seq; char* data(){(char*)(this+1)} }2.将文件分成若干块,在每块数据中加上包头,然后按顺序组播发送。3.发送端为每一个组播对象维护一个链表。用于记录每个组播对象收到(或没收到)的数据包4.接收端在收到每个数据包之后向发送端发送一个应答数据哦·,表示该数据包已收到。5.发送端在数据发送完毕之后,遍历每个组播对象的链表,重发组播对象没有接受到的数据包 http://topic.csdn.net/u/20100712/22/c4b467fd-e3d3-48c8-8deb-d89f19430ea0.htmlLZ去看看有没有你需要的~ 额 自己看看 完整的代码/************************************************************** *接收线程的回调函数 *发送的数据块结构解析: *类别 字节号 内容 *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; }} 假如我一次读取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)); } }那对方接受的时候会不会把这这一次发送的数据接受了,好多次呢? 如何将剪贴板中的文本粘贴为位图 用过MITK的解答一下问题,灰度的波形图的缩放是如何实现的? 套接字的问题 50分 明天答辩罗,散分 接分 一次双击有几次up和几次down VC ++ 的link不能产生debug info![错误内祥] 如何在vc中打开数据库后用嵌入式的sql查询 列表框的风格变换是如何实现的?就象explorer,可以切换小图标,大图标等...,哪里有例子,哪位能告诉我啊!!! 浏览器主页被占 定义控件相关的变量就报错,内存错误。怎么回事? RichEdit显示GIF CPU高
Struct SendData
{
uint8 nType; //数据包,应答包?
int Seq;
char* data(){(char*)(this+1)}
}
2.将文件分成若干块,在每块数据中加上包头,然后按顺序组播发送。
3.发送端为每一个组播对象维护一个链表。用于记录每个组播对象收到(或没收到)的数据包
4.接收端在收到每个数据包之后向发送端发送一个应答数据哦·,表示该数据包已收到。
5.发送端在数据发送完毕之后,遍历每个组播对象的链表,重发组播对象没有接受到的数据包
*接收线程的回调函数
*发送的数据块结构解析:
*类别 字节号 内容
*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;
}
}
假如我一次读取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));
} }
那对方接受的时候会不会把这这一次发送的数据接受了,好多次呢?