[转载]组播
(1)单播 一对一
(2)组播/广播 一对多 单点发送 多点接受 固定地址范围
根据internet NIC关于IP地址的规定,IP地址共分为A-E 共5类,其中A-C类目前应用的普通IP地址,E类地址保留为将来使用,D 类地址即为组播地址,其网络号为固定的1110(第0~3位),第4~31位定义了某一特殊的组播地址,范围为 224.0.0.0~239.255.255.255,共有228个约27亿个地址。
本文来自: (http://www.91linux.com/) 详细出处参考:http://www.91linux.com/html/article/network/20080616/12575_2.html
使用组播有一个很大的好处,消息往只管往里面丢,接受端开个线程,不断地接收就可以了。
发送端:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint iep = new IPEndPoint(IPAddress.Parse("224.0.0.1"), 3000);
EndPoint ep = (EndPoint)iep;
byte[] b = Encoding.ASCII.GetBytes("just a test!");
s.SendTo(b, ep);
s.Close();
接收端:
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, 3000);
EndPoint ep=(EndPoint)iep;
s.Bind(iep);
s.SetSocketOption(SocketOptionLevel.IP,SocketOptionName.AddMembership,new MulticastOption(IPAddress.Parse("224.0.0.1")));
byte[]b=new byte[1024];
s.ReceiveFrom(b,ref ep);
string test;
test = System.Text.Encoding.ASCII.GetString(b);
Console.WriteLine(test);
s.Close();
Console.ReadKey();
----------------------------------------------------------------------
上次说服务器的实现。下面说下交换机的实现(有点多):
分析:服务器和交换机的通信是一对一的。而交换机接收到数据还要把数据转发给机顶盒。而交换机-->机顶盒是通过组播。
1、交换机接收服务器的实现:
UINT RecvSendSTB1(void *p)
{
struct sockaddr_in addr;
int MultSock;
CIPTVSwitchDlg *pDlg=(CIPTVSwitchDlg*)p;
CString strIP;
CString m_strPort;
pDlg->m_IPAddr1.GetWindowText(strIP);//从界面获取IP
pDlg->m_PortEdit.GetWindowText(m_strPort);//从界面获取Port
pDlg->m_Port=atoi(m_strPort);
CString strTemp;
unsigned int IP_A;
strTemp=strIP.Mid(0, strIP.Find('.',0));
IP_A=atoi(strTemp);
if(IP_A<224 || IP_A>239 || pDlg->m_Port>65536)
{
AfxMessageBox("组播地址必须是224.0.0.0~239.255.255.254,而端口号必须是0~65535");
return -1;
}
else
{
/* create multicast UDP socket */
if ((MultSock=socket(AF_INET,SOCK_DGRAM,0)) < 0)
{
AfxMessageBox("Error create Multisok");
}
}
/* 设置组播地址 */
memset(&addr,0,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=inet_addr(strIP);
addr.sin_port=htons(pDlg->m_Port);
SOCKET socket1;
SOCKADDR_IN local;
SOCKADDR_IN from;
char buffer[1024];
char temp[1024];
memset(buffer,0,sizeof(buffer));
memset(temp,0,sizeof(temp));
char* pBuffer;
pBuffer=new char[4096];
pBuffer[0]='\0';
char* pBuf=pBuffer;
long iTemp = 0;
CString tmpPort;
pDlg->m_PortEdit4.GetWindowText(tmpPort);
pDlg->m_Port4=atoi(tmpPort);
//单播接收服务器数据sock
int fromlen =sizeof(SOCKADDR);
local.sin_family=AF_INET; //地址族,常被赋为AF_INET
local.sin_port=htons(pDlg->m_Port4); //监听端口
local.sin_addr.s_addr=INADDR_ANY; //本机IP
int ret=0;
ret=socket1=socket(AF_INET,SOCK_DGRAM,0);//数据报套接字
if(ret<0)
{
AfxMessageBox("socket创建失败");
}
//绑定套接字到一个IP地址和一个端口
if((bind(socket1,(SOCKADDR*)&local,sizeof(SOCKADDR))==SOCKET_ERROR))
{
AfxMessageBox("socket绑定失败");
}
//接收并组播发送数据
while(1)
{
int rev=0;
if((rev= recvfrom(socket1,buffer,sizeof(buffer),0,(SOCKADDR*)&from,&fromlen))<0)
{
AfxMessageBox("接收失败");
}
//组播发送
if (sendto(MultSock,buffer, rev, 0, (struct sockaddr *) &addr, sizeof(addr)) < 0)
{
AfxMessageBox("发送失败");
}
}
分析:要组播接收的方式接收交换机的数据。图像要显示出来(由于发送时设定了发送包的大小所以还要组包)。
接收数据和显示代码如下:
UINT ReceiveShowCh1(void *p)
{
CMultSocket m_SocketCh;
CCh1Dlg *pDlg=(CCh1Dlg*)p;
CString m_strIP;
CString m_strPort;
pDlg->m_IPAddrCh1.GetWindowText(m_strIP);
pDlg->m_PortCh1.GetWindowText(m_strPort);
pDlg->m_Port1=atoi(m_strPort);
CString strTemp;
unsigned int IP_A;
strTemp=m_strIP.Mid(0, m_strIP.Find('.',0));
IP_A=atoi(strTemp);
if(IP_A<224 || IP_A>239 || pDlg->m_Port1>65536)
{
AfxMessageBox("地址范围:224.0.0.0~239.255.255.254,端口号范围:0~65535");
return -1;
}
/*设置组播接收*/
int ret;
SOCKET SockCh1;
SOCKADDR_IN localAddr,remoteAddr;
int len = sizeof SOCKADDR;
char recvBuf[32000];
ip_mreq mcast; // 设置组播
SockCh1 = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if ( INVALID_SOCKET == SockCh1 )
{
WSACleanup();
return 1;
}
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(pDlg->m_Port1);
localAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
ret = bind(SockCh1,(SOCKADDR*)&localAddr,len);
if ( SOCKET_ERROR == ret )
{
closesocket(SockCh1);
return -1;
}
//用于接收组播所设置,把套接字加入一个组播
memset(&mcast,0x00,sizeof(mcast));
mcast.imr_multiaddr.S_un.S_addr = inet_addr(m_strIP);
mcast.imr_interface.S_un.S_addr = htonl(INADDR_ANY);
ret = setsockopt(SockCh1,IPPROTO_IP,IP_ADD_MEMBERSHIP,(char*)&mcast,sizeof(mcast));
if ( SOCKET_ERROR == ret )
{
AfxMessageBox("Error IP_Add");//printf("IP_ADD_MEMBERSHIP ERROR! CODE IS : %d\n",WSAGetLastError());
return -1;
}
memset(&remoteAddr,0x00,len);
memset(recvBuf,0x00,sizeof(recvBuf));
char *pBuf=new char[320000];
int iTemp=0;
int flags=0;
while (1)
{
ret = recvfrom(SockCh1,recvBuf,sizeof(recvBuf),0,(SOCKADDR*)&remoteAddr,&len);
if(flags)
{
if ( ret > 0 )
{
if(ret==1024)
{
for (int i=0; i<=ret; i++)
{
pBuf[i+iTemp] = recvBuf[i];
}
iTemp+=ret;
}
else
{
for (int i=0; i<=ret; i++)
{
pBuf[i+iTemp] = recvBuf[i];
}
iTemp+=ret;
//显示接收内容
pDlg->ShowPIC(pBuf,iTemp);
iTemp=0;
}
}
}
//过滤掉不完整的第一帧,一旦第一个小于1024的包,
//认为为图片的最后一个包,下一个为图片开始,flags置位
if(ret<1024)
{
flags=1;
}
}
return 0;
}
其中ShowPIC的代码如下:
void CCh1Dlg::ShowPIC(char* buf,int iSize)
{
IStream* m_pStream ;
IPicture* m_pPicture ;
LONG m_nWidth;
LONG m_nHeight;
HRESULT hr;
//上下文环境
CWnd *pPic =GetDlgItem(IDC_STATIC_Picture1);
pPic-> GetDC();
CClientDC dc(pPic);//CClientDC dc(this);
CRect rc;
HWND pWnd = pPic->GetSafeHwnd();
::GetWindowRect(pWnd,&rc);
m_pStream = NULL;
m_pPicture = NULL;
HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE,iSize);//开辟内存
hMem=buf;
hr = ::CreateStreamOnHGlobal(hMem,TRUE,&m_pStream);
ASSERT(SUCCEEDED(hr));
hr= ::OleLoadPicture(m_pStream,iSize,TRUE,IID_IPicture,(LPVOID *)&m_pPicture);
ASSERT(hr==S_OK);
//long nWidth,nHeight;宽高,MM_HIMETRIC 模式,单位是0.01毫米
m_pPicture->get_Width(&m_nWidth);//宽
m_pPicture->get_Height(&m_nHeight);//高
int w=rc.right-rc.left;
int h=rc.bottom-rc.top;
//根据窗口大小来显示
double tmppx=w*26.46;
double tmppy=h*26.46;
LONG px=(LONG)tmppx;
LONG py=(LONG)tmppy;
CSize sz(px,py);//图片显示的大小
dc.HIMETRICtoDP(&sz);
// 转换 MM_HIMETRIC 模式单位为 MM_TEXT 像素单位
m_pPicture->Render(dc.m_hDC,0,0,sz.cx,sz.cy,0,m_nHeight,m_nWidth,-m_nHeight,NULL);
}
到此结束了。这里只是贴了些部分实现的代码。自认写的不好很多可以改进的地方。贴出了就是想得到更多的改进
邮箱:steven9801@163.com
QQ: 48039387
浙公网安备 33010602011771号