请问如果服务器可能需要将大小不一(可能比较大,比如10k)的数据报分发到所有(可能有1万以上的)客户端? 请各位高手个一点建议吧?我以前很少接触网络编程。谢谢。 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 先发一个大小一样的包头给接收数据的客户端,比如一个结构体:struct MY_PACKET_HEAD{ DWORD dwFlag;//数据类型标志,可以自己定义,如果不需要也可以不用 DWORD dwDataSize;//接下来的数据包大小}然后客户端接收到这个包头之后就知道需要准备接收多少数据。 UDP IOCP模型,注意可以每次发送数据大小 你的这种情况应该用多播来实现,假如你不用多播,而用用tcp的连接来实现,每一个客户端发送到服务器的数据都要向其他的上万个连接进行转发,这样你的服务器肯定不堪重负,运行时间稍长,肯定崩溃。 请问有在internet上的多播实现的例子吗?谢谢 服务器端代码 /* * u_mctest.c (c) jack 4/9/2003 * * Released to the public domain * * Description: * Tries out BSD-compatible Multicast APIs, and sends multicast * messages in response to multicast messages received. *//*#ifndef _WIN32#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#else */#include <winsock2.h>#include <ws2tcpip.h>#include <stdio.h>//#endif#define BUFSIZE 1024#define TTL_VALUE 2#define TIME_OUT 10000/*IP多播提供了一种给一组主机传送消息的方法,组IP地址在IP数据报中的目的地址一栏中说明,具体格式与使用请参阅IP协议。组地址也称为D类IP地址,它的范围在224.0.0.0到239.255.255.255多播其实就是向某一个多播地址发送UDP数据报,这和UDP的传统形式没什么区别的每个多播地址代表一个多播组,而不是一台主机。IGMP(Internet组管理协议)用于控制用户加入或离开多播组,多播路由协议则用于建立多播路由表,或称多播树*/#define TEST_ADDR "234.5.6.7"#define TEST_PORT 9200#define LOOPMAX 20int main(){ struct sockaddr_in stLocal, stTo, stFrom; struct timeval timeval_val; //超时的结构 char achIn[BUFSIZE]; char achOut[] = "Message from server number: "; //要发送的信息 int s, i; struct ip_mreq stMreq; int iTmp, iRet;//#ifdef WIN32 /* Init WinSock */ WSADATA stWSAData; iTmp = WSAStartup(0x0202, &stWSAData); if (iTmp) { printf("WSAStartup failed: Err: %d\r\n", iTmp); exit (1); }//#endif /* get a datagram socket */ s = socket(AF_INET,SOCK_DGRAM,0); if (s == INVALID_SOCKET) { printf ("socket() failed, Err: %d\n", WSAGetLastError()); exit(1); } /* avoid EADDRINUSE error on bind() */ iTmp = TRUE; iRet = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&iTmp, sizeof(iTmp)); if (iRet == SOCKET_ERROR) { printf ("setsockopt() SO_REUSEADDR failed, Err: %d\n", WSAGetLastError()); } /* name the socket */ stLocal.sin_family = AF_INET; stLocal.sin_addr.s_addr = htonl(INADDR_ANY); stLocal.sin_port = htons(TEST_PORT); iRet = bind(s, (struct sockaddr*) &stLocal, sizeof(stLocal)); if (iRet == SOCKET_ERROR) { printf ("bind() failed, Err: %d\n", WSAGetLastError()); } /* join the multicast group. */ stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR); stMreq.imr_interface.s_addr = INADDR_ANY; iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq,sizeof(stMreq)); if (iRet == SOCKET_ERROR) { printf ("setsockopt() IP_ADD_MEMBERSHIP failed, Err: %d\n", WSAGetLastError()); } /* set TTL to traverse up to multiple routers */ iTmp = TTL_VALUE; iRet = setsockopt( s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&iTmp, sizeof(iTmp) ); if (iRet == SOCKET_ERROR) { printf ("setsockopt() IP_MULTICAST_TTL failed, Err: %d\n", WSAGetLastError()); } /* 设置接受数据超时*/ /* timeval_val.tv_sec = 10;//10秒为超时 timeval_val.tv_usec = 1000000; iRet = setsockopt( s, IPPROTO_IP, SO_RCVTIMEO, (char*)&timeval_val, sizeof(timeval_val) ); if( iRet == SOCKET_ERROR ) { printf ("setsockopt() SO_RCVTIMEO failed, Err: %d\n",WSAGetLastError()); }*/ /* disable loopback */ iTmp = FALSE; iRet = setsockopt( s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&iTmp, sizeof(iTmp)); if (iRet == SOCKET_ERROR) { printf ("setsockopt() IP_MULTICAST_LOOP failed, Err: %d\n", WSAGetLastError()); } /* assign our destination address */ stTo.sin_family = AF_INET; stTo.sin_addr.s_addr = inet_addr(TEST_ADDR); stTo.sin_port = htons(TEST_PORT); for (i=0;i<LOOPMAX;i++) { int addr_size = sizeof(struct sockaddr_in); static iCounter = 1; printf ("Now receiving multicast group: %s\n", TEST_ADDR); iRet = recvfrom( s, achIn, BUFSIZE, 0, (struct sockaddr*)&stFrom, &addr_size); if (iRet < 0) { printf ("recvfrom() failed, Error: %d\n", WSAGetLastError()); exit(1); } //inet_ntoa(stFrom.sin_addr)函数将32位的IP地址转化成IP地址字符串 printf( "From host:%s port:%d, %s\n", inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port), achIn ); /* send to the multicast address */ itoa(iCounter++, &achOut[16], 10); printf ("Now sending to multicast group: %s\n",TEST_ADDR); iRet = sendto(s, achOut, sizeof(achOut), 0, (struct sockaddr*)&stTo, addr_size); if (iRet < 0) {// perror("sendto() failed\n"); printf ("sendto() failed, Error: %d\n", WSAGetLastError()); exit(1); } } /* end for(;;) *///#ifdef WIN32 /* sign-off WinSock */ WSACleanup();//#endif} /* end main() *//*多播包的目的地址使用D类IP地址,即从224.0.0.0到239.255.255.255的多播地址。每个多播地址代表一个多播组,而不是一台主机。IGMP(Internet组管理协议)用于控制用户加入或离开多播组,多播路由协议则用于建立多播路由表或称多播树。 。。如果一个局域网中有一个用户通过IGMP宣布加入某多播组,局域网中的多播路由器就将该信息通过多播路由协议进行传播,最终将该局域网作为一个分枝加入多播树。当局域网中的所有用户退出该多播组后,相关的分枝就从多播树中删掉。多播网中可能有不支持多播的路由器,此时多播路由器使用“IP over IP”的隧道方式将多播包封装在单播IP包中传给相邻的多播路由器,相邻的多播路由器再将单播IP头剥掉,然后继续进行多播传输*//*多播是一种点到多点(多点到多点)的通信方式,即多个接收者同时接收一个源发送的相同信息。在多播中,组的概念十分重要。由多播定义可知,多播报文是从一个源发到三组目的节点。在IP多播中,多播组有一个ID号,称作多播组ID号,它指定发送报文的目的组,实际上是D类ID地址。主机若要接收发到一个特定组的多播报文,就要监听发往该特定组的所有报文。为了解决因特网上多播报文的选路,主机须通过通知其子网上的多播路由器来加入一个组,多播中采用因特网组管理协议(IGMP)来达到此目的。 *//*除了网络中的节点不必协助发现以外,多播模型和网络模型很相似。这种模型利用网络自身提供的特性来定位和确认对等点和资源。这种技术的实现(Sun Microsystems 的 Project Jxta 是一个极佳的示例;有关 Jxta的更多信息,请参阅参考资料)使用 IP 多播来实现查询。不象单播(unicast) IP 数据报 — 一台主机,最多只能向一台主机发送数据报,多播 IP 数据报可以同时发往多台主机。更重要的是,发送方不必知道有多少接收方存在或者究竟有没有接收方存在。发送主机只是封装消息并将它发布到网络上。所有调整到适当频道(特殊 IP 地址和端口号的组合)的客户机将接收到该消息的一个副本。使用 IP 多播技术的发现通过让对等点用多播定期宣布自己的存在来工作。该消息包含对等点的 TCP/IP 主机名和端口号。对此消息感兴趣的对等点检测这个消息后,抽取出主机名和端口号,并使用这个信息与新对等点建立正常的 TCP/IP 连接。这就是多播是如何在单个子网上工作的。众多子网(组成整个网络)间的路由多播通信是完全不同的,并且是一个非常复杂的课题。这也是基于 IP 多播的发现的主要局限。没有路由器的支持,基于 IP 多播的发现被局限在同一子网上的对等点之间。不幸的是,因特网对多播并不友好。通常,因特网(或大型内部网)上的发现由跨网络边界的特殊对等点将消息复制到另一个网络中来实现。*/ internet网络上可以使用多播吗,是否可以查询到网络是否支持多播?我看一些网上的评论说现在的很多路由都不允许多播?是这样的吗? ActiveX 暴风影音控件 求助 _variant_t问题 一个极难的VC小问题,测测自己的水平怎样?? MAPI问题 请大侠帮手:如何获取所有窗口的句柄? 高人指教,关于OFFICE嵌入按扭能否贴入长方形的图标 用SOCKET发数据,数据量有点大,经常阻塞,怎么办? 为什么修改对话框的类名后,创建无模式对话框会失败? MFC串口编程,get_input()函数意外退出 请问如何在按钮上加入位图? 切换到Release模式后编译报警告? SDK编程``怎样建个RichText?
struct MY_PACKET_HEAD
{
DWORD dwFlag;//数据类型标志,可以自己定义,如果不需要也可以不用
DWORD dwDataSize;//接下来的数据包大小
}
然后客户端接收到这个包头之后就知道需要准备接收多少数据。
谢谢
* u_mctest.c (c) jack 4/9/2003
*
* Released to the public domain
*
* Description:
* Tries out BSD-compatible Multicast APIs, and sends multicast
* messages in response to multicast messages received.
*/
/*#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#else */
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
//#endif#define BUFSIZE 1024
#define TTL_VALUE 2
#define TIME_OUT 10000/*IP多播提供了一种给一组主机传送消息的方法,组IP地址在IP数据报中的目的地址一栏中说明,
具体格式与使用请参阅IP协议。组地址也称为D类IP地址,它的范围在224.0.0.0到239.255.255.255
多播其实就是向某一个多播地址发送UDP数据报,这和UDP的传统形式没什么区别的每个多播地址代表一个多播组,而不是一台主机。IGMP(Internet组管理协议)
用于控制用户加入或离开多播组,多播路由协议则用于建立多播路由表,或称多播树*/#define TEST_ADDR "234.5.6.7"
#define TEST_PORT 9200
#define LOOPMAX 20int main()
{
struct sockaddr_in stLocal, stTo, stFrom;
struct timeval timeval_val; //超时的结构
char achIn[BUFSIZE];
char achOut[] = "Message from server number: "; //要发送的信息
int s, i;
struct ip_mreq stMreq;
int iTmp, iRet;
//#ifdef WIN32
/* Init WinSock */
WSADATA stWSAData;
iTmp = WSAStartup(0x0202, &stWSAData);
if (iTmp)
{
printf("WSAStartup failed: Err: %d\r\n", iTmp);
exit (1);
}
//#endif /* get a datagram socket */
s = socket(AF_INET,SOCK_DGRAM,0);
if (s == INVALID_SOCKET)
{
printf ("socket() failed, Err: %d\n", WSAGetLastError());
exit(1);
} /* avoid EADDRINUSE error on bind() */
iTmp = TRUE;
iRet = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&iTmp, sizeof(iTmp));
if (iRet == SOCKET_ERROR)
{
printf ("setsockopt() SO_REUSEADDR failed, Err: %d\n",
WSAGetLastError());
} /* name the socket */
stLocal.sin_family = AF_INET;
stLocal.sin_addr.s_addr = htonl(INADDR_ANY);
stLocal.sin_port = htons(TEST_PORT);
iRet = bind(s, (struct sockaddr*) &stLocal, sizeof(stLocal));
if (iRet == SOCKET_ERROR)
{
printf ("bind() failed, Err: %d\n",
WSAGetLastError());
} /* join the multicast group. */
stMreq.imr_multiaddr.s_addr = inet_addr(TEST_ADDR);
stMreq.imr_interface.s_addr = INADDR_ANY;
iRet = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&stMreq,sizeof(stMreq));
if (iRet == SOCKET_ERROR)
{
printf ("setsockopt() IP_ADD_MEMBERSHIP failed, Err: %d\n",
WSAGetLastError());
} /* set TTL to traverse up to multiple routers */
iTmp = TTL_VALUE;
iRet = setsockopt( s, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&iTmp, sizeof(iTmp) );
if (iRet == SOCKET_ERROR)
{
printf ("setsockopt() IP_MULTICAST_TTL failed, Err: %d\n",
WSAGetLastError());
} /* 设置接受数据超时*/
/* timeval_val.tv_sec = 10;//10秒为超时
timeval_val.tv_usec = 1000000;
iRet = setsockopt( s, IPPROTO_IP, SO_RCVTIMEO, (char*)&timeval_val, sizeof(timeval_val) );
if( iRet == SOCKET_ERROR )
{
printf ("setsockopt() SO_RCVTIMEO failed, Err: %d\n",WSAGetLastError()); }*/
/* disable loopback */
iTmp = FALSE;
iRet = setsockopt( s, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&iTmp, sizeof(iTmp));
if (iRet == SOCKET_ERROR)
{
printf ("setsockopt() IP_MULTICAST_LOOP failed, Err: %d\n",
WSAGetLastError());
} /* assign our destination address */
stTo.sin_family = AF_INET;
stTo.sin_addr.s_addr = inet_addr(TEST_ADDR);
stTo.sin_port = htons(TEST_PORT);
for (i=0;i<LOOPMAX;i++)
{
int addr_size = sizeof(struct sockaddr_in);
static iCounter = 1; printf ("Now receiving multicast group: %s\n", TEST_ADDR);
iRet = recvfrom( s, achIn, BUFSIZE, 0, (struct sockaddr*)&stFrom, &addr_size);
if (iRet < 0)
{ printf ("recvfrom() failed, Error: %d\n", WSAGetLastError());
exit(1);
} //inet_ntoa(stFrom.sin_addr)函数将32位的IP地址转化成IP地址字符串
printf( "From host:%s port:%d, %s\n", inet_ntoa(stFrom.sin_addr), ntohs(stFrom.sin_port), achIn );
/* send to the multicast address */
itoa(iCounter++, &achOut[16], 10);
printf ("Now sending to multicast group: %s\n",TEST_ADDR);
iRet = sendto(s, achOut, sizeof(achOut), 0, (struct sockaddr*)&stTo, addr_size);
if (iRet < 0)
{
// perror("sendto() failed\n");
printf ("sendto() failed, Error: %d\n", WSAGetLastError());
exit(1);
}
} /* end for(;;) *///#ifdef WIN32
/* sign-off WinSock */
WSACleanup();
//#endif} /* end main() */
/*多播包的目的地址使用D类IP地址,即从224.0.0.0到239.255.255.255的多播地址。每个多播地址代表一个多播组,而不是一台主机。IGMP(Internet组管理协议)用于控制用户加入或离开多播组,多播路由协议则用于建立多播路由表或称多播树。 。。如果一个局域网中有一个用户通过IGMP宣布加入某多播组,局域网中的多播路由器就将该信息通过多播路由协议进行传播,最终将该局域网作为一个分枝加入多播树。当局域网中的所有用户退出该多播组后,相关的分枝就从多播树中删掉。多播网中可能有不支持多播的路由器,此时多播路由器使用“IP over IP”的隧道方式将多播包封装在单播IP包中传给相邻的多播路由器,相邻的多播路由器再将单播IP头剥掉,然后继续进行多播传输
*/
/*多播是一种点到多点(多点到多点)的通信方式,即多个接收者同时接收一个源发送的相同信息。在多播中,组的概念十分重要。由多播定义可知,多播报文是从一个源发到三组目的节点。在IP多播中,多播组有一个ID号,称作多播组ID号,它指定发送报文的目的组,实际上是D类ID地址。主机若要接收发到一个特定组的多播报文,就要监听发往该特定组的所有报文。为了解决因特网上多播报文的选路,主机须通过通知其子网上
的多播路由器来加入一个组,多播中采用因特网组管理协议(IGMP)来达到此目的。 */
/*除了网络中的节点不必协助发现以外,多播模型和网络模型很相似。这种模型利用网络自身提供的特性来定位和确认对等点和资源。这种技术的实现(Sun Microsystems 的 Project Jxta 是一个极佳的示例;有关 Jxta的更多信息,请参阅参考资料)使用 IP 多播来实现查询。不象单播(unicast) IP 数据报 — 一台主机,最多只能向一台主机发送数据报,多播 IP 数据报可以同时发往多台主机。更重要的是,发送方不必知道有多少接收方存在或者究竟有没有接收方存在。发送主机只是封装消息并将它发布到网络上。所有调整到适当频道(特殊 IP 地址和端口号的组合)的客户机将接收到该消息的一个副本。使用 IP 多播技术的发现通过让对等点用多播定期宣布自己的存在来工作。该消息包含对等点的 TCP/IP 主机名和端口号。对此消息感兴趣的对等点检测这个消息后,抽取出主机名和端口号,并使用这个信息与新对等点建立正常的 TCP/IP 连接。这就是多播是如何在单个子网上工作的。众多子网(组成整个网络)间的路由多播通信是完全不同的,并且是一个非常复杂的课题。这也是基于 IP 多播的发现的主要局限。没有路由器的支持,基于 IP 多播的发现被局限在同一子网上的对等点之间。
不幸的是,因特网对多播并不友好。通常,因特网(或大型内部网)上的发现由跨网络边界的特殊对等点将消息复制到另一个网络中来实现。
*/
我看一些网上的评论说现在的很多路由都不允许多播?
是这样的吗?