多播(自发自收)

本文介绍了一个使用Winsock实现多播通信的C语言示例程序。该程序首先检查系统是否安装了合适的Winsock DLL版本,然后创建一个多播套接字,并进行必要的配置如设置TTL和启用LOOPBACK等,最后在一个循环中发送和接收数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#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; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值