0
点赞
收藏
分享

微信扫一扫

多播(自发自收)

#include <winsock2.h>
#include <stdio.h>
#define BUFSIZE 1024
#define MAXADDRSTR 16
#define LOOPCOUNT 100
/* 检查系统中是否安装了合适版本的Winsock DLL。*/
int CheckWinsockVersion(void)
{
WORD wVersionRequested;
WSADATA wsaData;

int err;
// 异步I/O和多址广播只有在Winsock2.0以上版本才支持
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err == 0)
{
if ((LOBYTE(wsaData.wVersion) == 2) && (HIBYTE(wsaData.wVersion) == 2))
{
// 确认Winsock DLL 支持2.0
return 0;
}
WSACleanup();
err = WSAVERNOTSUPPORTED; // 不支持,失败返回
}

/* Tell the user that we couldn't find a usable WinsockDLL. */
printf("Winsock DLL does not support requested API version./n");
return err;
}
int main()
{
int nRet, i;
int nIP_TTL = 1; // 在本子网中传播
BOOL bFlag;
DWORD dFlag, cbRet;
int iLen = MAXADDRSTR;
char strDestMulti[MAXADDRSTR] = "224.1.1.1";
SOCKADDR_IN stSrcAddr, stDestAddr;
SOCKET hSock, hNewSock;
u_short nDestPort = 6666;
WSABUF stWSABuf;
char achInBuf[BUFSIZE];
char achOutBuf[] = "Message number: ";

nRet = CheckWinsockVersion(); // 检测Winsock版本号
if (nRet)
{
printf("WSAStartup failed: %d/r/n", nRet);
exit(1);
}

// 将字符串地址转化成套接字地址
nRet = WSAStringToAddress(strDestMulti, // address string
AF_INET, // address family
NULL, // protocol info structure
(LPSOCKADDR)&stDestAddr, // socket address string
&iLen); // length of socket structure
if (nRet)
{
printf("WSAStringToAddress(%s)failed,Err:%d/n", strDestMulti, WSAGetLastError());
exit(1);
}

// 创建一个多播套接字
hSock = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
(LPWSAPROTOCOL_INFO)NULL, 0, WSA_FLAG_OVERLAPPED | WSA_FLAG_MULTIPOINT_C_LEAF | WSA_FLAG_MULTIPOINT_D_LEAF);
if (hSock == INVALID_SOCKET)
{
printf("WSASock() failed, Err:%d/n", WSAGetLastError());
exit(1);
}

bFlag = TRUE; // 设置套接口为可重用端口地址
nRet = setsockopt(hSock, // socket
SOL_SOCKET, // socket level
SO_REUSEADDR, // socket option
(char*)&bFlag, // option value
sizeof(bFlag)); // size of value
if (nRet == SOCKET_ERROR)
{
printf("setsockopt() SO_REUSEADDR failed,Err:%d/n", WSAGetLastError());
}

// 将套接口绑定到用户指定端口及默认的接口
stSrcAddr.sin_family = PF_INET;
stSrcAddr.sin_port = htons(nDestPort);
stSrcAddr.sin_addr.s_addr = INADDR_ANY;
nRet = bind(hSock, (struct sockaddr FAR*)&stSrcAddr, sizeof(struct sockaddr));

if (nRet == SOCKET_ERROR)
{
printf("bind failed, Err:%d/n", WSAGetLastError());
exit(1);
}

// 设置多播数据报传送范围(TTL)
nRet = WSAIoctl(hSock,
SIO_MULTICAST_SCOPE,
&nIP_TTL,
sizeof(nIP_TTL),
NULL,
0,
&cbRet,
NULL,
NULL);
if (nRet)
{
printf("WSAIoctl(SIO_MULTICAST_SCOPE) failed, Err:%d/n", WSAGetLastError());
exit(0);
}
// 允许内部回送(LOOPBACK)。Windows 95不支持该选项
bFlag = TRUE;
nRet = WSAIoctl(hSock,
SIO_MULTIPOINT_LOOPBACK,
&bFlag,
sizeof(bFlag),
NULL,
0,
&cbRet,
NULL,
NULL);
if (nRet)
{
printf("WSAIoctl(SIO_MULTIPOINT_LOOPBACK)failed, Err: %d/n", WSAGetLastError());
exit(0);
}

stDestAddr.sin_family = AF_INET;
nRet = WSAHtons(hSock,
nDestPort,
&(stDestAddr.sin_port));
if (nRet == SOCKET_ERROR)
{
printf("WSAHtons() failed, Err: %d/n", WSAGetLastError());
exit(0);
}

// 加入到指定多址广播组,指定为即为发送者又做接收者
// 在IP Multicast中,返回的套接字描述符和输入的套接字描述符相同
hNewSock = WSAJoinLeaf(hSock,
(PSOCKADDR)&stDestAddr,
sizeof(stDestAddr),
NULL,
NULL,
NULL,
NULL,
JL_BOTH);
if (hNewSock == INVALID_SOCKET)
{
printf("WSAJoinLeaf() failed, Err: %d/n", WSAGetLastError());
exit(0);
}

// 在循环中发送/接收数据。
for (i = 0; i < LOOPCOUNT; i++)
{
static iCounter = 1;
stWSABuf.buf = achOutBuf;
stWSABuf.len = sizeof(achOutBuf);

cbRet = 0;
itoa(iCounter++, &achOutBuf[16], 10);
nRet = WSASendTo(hSock,
&stWSABuf,
1,
&cbRet,
0,
(struct sockaddr*)&stDestAddr,
sizeof(struct sockaddr),
NULL,
NULL);
if (nRet == SOCKET_ERROR)
{
printf("WSASendTo() failed. Err: %d/n", WSAGetLastError());
exit(0);
}
stWSABuf.buf = achInBuf;
stWSABuf.len = BUFSIZE;
cbRet = 0;
iLen = sizeof(stSrcAddr);
dFlag = 0;

nRet = WSARecvFrom(hSock,
&stWSABuf,
1,
&cbRet,
&dFlag,
(struct sockaddr*)&stSrcAddr,
&iLen,
NULL,
NULL);
if (nRet == SOCKET_ERROR)
{
printf("WSARecvFrom() failed, Err:%d/n", WSAGetLastError());
exit(0);
}
else
{
u_short nPort = 0;
char achAddr[MAXADDRSTR + 3] = {0};
iLen = MAXADDRSTR + 3;
nRet = WSAAddressToString(
(struct sockaddr*)&stSrcAddr,
sizeof(stSrcAddr),
NULL,
achAddr,
(unsigned long*)&iLen);
if (nRet == SOCKET_ERROR)
{
printf("WSAAddressToString() failed, Err:%d/n", WSAGetLastError());
exit(0);
}
nRet = WSANtohs(hSock,
stSrcAddr.sin_family,
&nPort);
if (nRet == SOCKET_ERROR)
{
printf("WSANtohs() failed, Err:%d/n", WSAGetLastError());
exit(0);
}

printf("received %d bytes from %s, port %d:%s/r/n",
cbRet, achAddr[0] ? achAddr : "??", nPort, achInBuf);
}
}

closesocket(hNewSock);
closesocket(hSock);
WSACleanup();
return 0;
}

举报

相关推荐

0 条评论