socket组播出现的问题记录
程序员文章站
2022-04-24 14:26:13
...
这个程序需要绑定两个端口:
1.通过端口复用的方法,绑定同一个端口;
2.接收和发送用不同的端口,在发送函数填入组播地址和发送端的端口号。
/*加载库文件*/
#pragma comment( lib, "ws2_32.lib" )
/*加载头文件*/
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
/*定义多播常量*/
#define MCASTADDR "224.3.5.8"
#define MCASTPORT 25000
#define BUFSIZE 1024
#define MCOUNT 10
/*定义广播常量*/
#define BCASTPORT 5050
#define BCOUNT 10
/*定义广播全局变量*/
SOCKET socketBro;
SOCKET socketRec;
struct sockaddr_in addrBro;
struct sockaddr_in addrRec;
BOOL broadSendFlag;
BOOL broadFlag;
DWORD bCount;
DWORD bcastAddr;
short bPort;
/*定义多播全局变量*/
SOCKET socketMul;
SOCKET sockJoin;
struct sockaddr_in addrLocal;
struct sockaddr_in addrMul;
BOOL multiSendFlag;
BOOL bLoopBack;
BOOL multiFlag;
DWORD dwInterface;
DWORD dwMulticastGroup;
DWORD mCount;
short mPort;
/*自定义函数*/
void initial();
void GetArgments(int argc, char **argv);
void userHelpAll();
void userHelpBro();
void userHelpMul();
void broadcastSend();
void broadcastRec();
void mulControl();
void multicastSend();
void multicastRec();
/*初始化全局变量函数*/
void initial()
{
/*初始化广播全局变量*/
bPort = BCASTPORT;
bCount = BCOUNT;
bcastAddr = INADDR_BROADCAST;
broadSendFlag = FALSE;
broadFlag = FALSE;
multiFlag = FALSE;
/*初始化多播全局变量*/
dwInterface = INADDR_ANY;
dwMulticastGroup = inet_addr(MCASTADDR);
mPort = MCASTPORT;
mCount = MCOUNT;
multiSendFlag = FALSE;
bLoopBack = FALSE;
}
/*参数获取函数*/
void GetArgments(int argc, char **argv)
{
int i;
/*如果参数个数小于2个*/
if (argc <= 1)
{
userHelpAll();
return;
}
/*获取广播选项*/
if (argv[1][0] == '-'&&argv[1][1] == 'b')
{
/*广播标志设置为真*/
broadFlag = TRUE;
for (i = 2; i < argc;i++)
{
if (argv[i][0] == '-')
{
switch (tolower(argv[i][1]))
{
/*如果是发送者*/
case 's':
broadSendFlag = TRUE;
break;
/*广播的地址*/
case 'h':
if (strlen(argv[i]) > 3)
bcastAddr = inet_addr(&argv[i][3]);
break;
/*广播的端口号*/
case 'p':
if (strlen(argv[i]) > 3)
bPort = atoi(&argv[i][3]);
break;
/*广播(接收或者发送)的数量*/
case 'n':
bCount = atoi(&argv[i][3]);
break;
/*其他情况显示用户帮助,终止程序*/
default:
{
userHelpBro();
ExitProcess(-1);
}
break;
}
}
}
return;
}
/*获取多播选项*/
if (argv[1][0] == '-'&&argv[1][1] == 'm')
{
/*多播标志设置为真*/
multiFlag = TRUE;
for (i = 2; i < argc;i++)
{
if (argv[i][0] == '-')
{
switch (tolower(argv[i][1]))
{
/*如果是发送者*/
case 's':
multiSendFlag = TRUE;
break;
/*多播地址*/
case 'h':
if (strlen(argv[i]) > 3)
dwMulticastGroup = inet_addr(&argv[i][3]);
break;
/*本地接口地址*/
case 'i':
if (strlen(argv[i]) > 3)
dwInterface = inet_addr(&argv[i][3]);
break;
/*多播端口号*/
case 'p':
if (strlen(argv[i]) > 3)
mPort = atoi(&argv[i][3]);
break;
/*环回标志设置为真*/
case 'l':
bLoopBack = TRUE;
break;
/*发送(接收)的数量*/
case 'n':
mCount = atoi(&argv[i][3]);
break;
/*其他情况,显示用户帮助,终止程序*/
default:
userHelpMul();
break;
}
}
}
}
return;
}
/*全局用户帮助函数*/
void userHelpAll()
{
printf("Please choose broadcast[-b] or multicast[-m] !\n");
printf("userHelpAll: -b [-s][p][-h][-n] | -m[-s][-h][-p][-i][-l][-n]\n");
userHelpBro();
userHelpMul();
}
/*广播用户帮助函数*/
void userHelpBro()
{
printf("Broadcast: -b -s:str -p:int -h:str -n:int\n");
printf(" -b Start the broadcast program.\n");
printf(" -s Act as server (send data); otherwise\n");
printf(" receive data. Default is receiver.\n");
printf(" -p:int Port number to use\n ");
printf(" The default port is 5050.\n");
printf(" -h:str The decimal broadcast IP address.\n");
printf(" -n:int The Number of messages to send/receive.\n");
printf(" The default number is 10.\n");
}
/*多播用户帮助函数*/
void userHelpMul()
{
printf("Multicast: -m -s -h:str -p:int -i:str -l -n:int\n");
printf(" -m Start the multicast program.\n");
printf(" -s Act as server (send data); otherwise\n");
printf(" receive data. Default is receiver.\n");
printf(" -h:str The decimal multicast IP address to join\n");
printf(" The default group is: %s\n", MCASTADDR);
printf(" -p:int Port number to use\n");
printf(" The default port is: %d\n", MCASTPORT);
printf(" -i:str Local interface to bind to; by default \n");
printf(" use INADDRY_ANY\n");
printf(" -l Disable loopback\n");
printf(" -n:int Number of messages to send/receive\n");
ExitProcess(-1);
}
/*广播消息发送函数*/
void broadcastSend()
{
/*设置广播的消息*/
char *smsg = "The message received is from sender!";
BOOL opt = TRUE;
int nlen = sizeof(addrBro);
int ret;
DWORD i = 0;
/*创建UDP套接字*/
socketBro = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
/*如果创建失败*/
if (socketBro == INVALID_SOCKET)
{
printf("Create socket failed:%d\n", WSAGetLastError());
WSACleanup();
return;
}
/*设置广播地址各个选项*/
addrBro.sin_family = AF_INET;
addrBro.sin_addr.s_addr = bcastAddr;
addrBro.sin_port = htons(bPort);
/*设置该套接字为广播类型*/
if (setsockopt(socketBro, SOL_SOCKET, SO_BROADCAST, (char FAR *)&opt,
sizeof(opt)) == SOCKET_ERROR)
/*如果设置失败*/
{
printf("setsockopt failed:%d", WSAGetLastError());
closesocket(socketBro);
WSACleanup();
return;
}
/*循环发送消息*/
while (i<bCount)
{
/*延迟1秒*/
Sleep(1000);
/*从广播地址发送消息*/
ret = sendto(socketBro, smsg, 256, 0, (struct sockaddr*)&addrBro, nlen);
/*如果发送失败*/
if (ret == SOCKET_ERROR)
printf("Send failed:%d", WSAGetLastError());
/*如果发送成功*/
else
{
printf("Send message %d!\n", i);
}
i++;
}
/*发送完毕后关闭套接字、释放占用资源*/
closesocket(socketBro);
WSACleanup();
}
/*广播消息接收函数*/
void broadcastRec()
{
BOOL optval = TRUE;
int addrBroLen;
char buf[256];
DWORD i = 0;
/*该地址用来绑定套接字*/
addrRec.sin_family = AF_INET;
addrRec.sin_addr.s_addr = 0;
addrRec.sin_port = htons(bPort);
/*该地址用来接收网路上广播的消息*/
addrBro.sin_family = AF_INET;
addrBro.sin_addr.s_addr = bcastAddr;
addrBro.sin_port = htons(bPort);
addrBroLen = sizeof(addrBro);
//创建UDP套接字
socketRec = socket(AF_INET, SOCK_DGRAM, 0);
/*如果创建失败*/
if (socketRec == INVALID_SOCKET)
{
printf("Create socket error:%d", WSAGetLastError());
WSACleanup();
return;
}
/*设置该套接字为可重用类型*/
if (setsockopt(socketRec, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&optval,
sizeof(optval)) == SOCKET_ERROR)
/*如果设置失败*/
{
printf("setsockopt failed:%d", WSAGetLastError());
closesocket(socketRec);
WSACleanup();
return;
}
/*绑定套接字和地址*/
if (bind(socketRec, (struct sockaddr *)&addrRec,
sizeof(struct sockaddr_in)) == SOCKET_ERROR)
/*如果绑定失败*/
{
printf("bind failed with: %d\n", WSAGetLastError());
closesocket(socketRec);
WSACleanup();
return;
}
/*从广播地址接收消息*/
while (i<bCount)
{
recvfrom(socketRec, buf, 256, 0, (struct sockaddr FAR *)&addrBro, (int FAR *)&addrBroLen);
/*延迟2秒钟*/
Sleep(2000);
/*输出接收到缓冲区的消息*/
printf("%s\n", buf);
printf("from address:%s\n", inet_ntoa(addrBro.sin_addr));
/*情况缓冲区*/
ZeroMemory(buf, 256);
i++;
}
/*接收完毕后关闭套接字、释放占用资源*/
closesocket(socketRec);
WSACleanup();
}
/*多播控制函数*/
void mulControl()
{
int optval;
/*创建UDP套接字,用于多播*/
if ((socketMul = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0,
WSA_FLAG_MULTIPOINT_C_LEAF
| WSA_FLAG_MULTIPOINT_D_LEAF
| WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("socket failed with: %d\n", WSAGetLastError());
WSACleanup();
return;
}
/*设置本地接口地址*/
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(mPort);
addrLocal.sin_addr.s_addr = dwInterface;
/*设置该套接字为可重用类型*/
optval = 1;
if (setsockopt(socketMul, SOL_SOCKET, SO_REUSEADDR, (char FAR *)&optval,
sizeof(optval)) == SOCKET_ERROR)
/*如果设置失败*/
{
printf("setsockopt failed:%d", WSAGetLastError());
closesocket(socketMul);
WSACleanup();
return;
}
/*将UDP套接字绑定到本地地址上*/
if (bind(socketMul, (struct sockaddr *)&addrLocal,
sizeof(addrLocal)) == SOCKET_ERROR)
/*如果绑定失败*/
{
printf("bind failed with: %d\n", WSAGetLastError());
closesocket(socketMul);
WSACleanup();
return;
}
/*设置多播地址各个选项*/
addrMul.sin_family = AF_INET;
addrMul.sin_port = htons(mPort);
addrMul.sin_addr.s_addr = dwMulticastGroup;
/*重新设置TTL值*/
optval = 8;
/*设置多播数据的TTL(存在时间)值。默认情况下,TTL值是1*/
if (setsockopt(socketMul, IPPROTO_IP, IP_MULTICAST_TTL,
(char *)&optval, sizeof(int)) == SOCKET_ERROR)
/*如果设置失败*/
{
printf("setsockopt(IP_MULTICAST_TTL) failed: %d\n", WSAGetLastError());
closesocket(socketMul);
WSACleanup();
return;
}
/*如果指定了返还选项*/
if (bLoopBack)
{
/*设置返还选项为假,禁止将发送的数据返还给本地接口*/
optval = 0;
if (setsockopt(socketMul, IPPROTO_IP, IP_MULTICAST_LOOP,
(char *)&optval, sizeof(optval)) == SOCKET_ERROR)
/*如果设置失败*/
{
printf("setsockopt(IP_MULTICAST_LOOP) failed: %d\n",
WSAGetLastError());
closesocket(socketMul);
WSACleanup();
return;
}
}
/*加入多播组*/
if ((sockJoin = WSAJoinLeaf(socketMul, (SOCKADDR *)&addrMul,
sizeof(addrMul), NULL, NULL, NULL, NULL,
JL_BOTH)) == INVALID_SOCKET)
/*如果加入不成功*/
{
printf("WSAJoinLeaf() failed: %d\n", WSAGetLastError());
closesocket(socketMul);
WSACleanup();
return;
}
}
void multicastSend()
{
CHAR sendbuf[BUFSIZE];
DWORD i;
int ret;
mulControl();
/*发送mCount条消息*/
//addrMul.sin_port= htons(10001);在这里输入接收进程的端口
addrMul.sin_port = htons(mPort);
for (i = 0; i < mCount; i++)
{
/*将待发送的消息写入发送缓冲区*/
sprintf(sendbuf, "server 1: This is a test: %d", i);
ret = sendto(socketMul, (char *)sendbuf, strlen(sendbuf), 0,
(struct sockaddr *)&addrMul, sizeof(addrMul));
/*如果发送失败*/
if (ret == SOCKET_ERROR)
{
printf("sendto failed with: %d\n", WSAGetLastError());
closesocket(sockJoin);
closesocket(socketMul);
WSACleanup();
return;
}
/*如果发送成功*/
else
printf("Send message %d\n", i);
Sleep(500);
}
/*关闭套接字、释放占用资源*/
closesocket(socketMul);
WSACleanup();
}
/*多播消息接收函数*/
void multicastRec()
{
DWORD i;
struct sockaddr_in from;
CHAR recvbuf[BUFSIZE];
int ret;
int len = sizeof(struct sockaddr_in);
mulControl();
/*接收mCount条消息*/
for (i = 0; i < mCount; i++)
{
/*将接收的消息写入接收缓冲区*/
if ((ret = recvfrom(socketMul, recvbuf, BUFSIZE, 0,
(struct sockaddr *)&from, &len)) == SOCKET_ERROR)
/*如果接收不成功*/
{
printf("recvfrom failed with: %d\n", WSAGetLastError());
closesocket(sockJoin);
closesocket(socketMul);
WSACleanup();
return;
}
/*接收成功,输出接收的消息*/
recvbuf[ret] = 0;
printf("RECV: '%s' from <%s>\n", recvbuf, inet_ntoa(from.sin_addr));
}
/*关闭套接字、释放占用资源*/
closesocket(socketMul);
WSACleanup();
}
/*主函数*/
int main(int argc, char **argv)
{
WSADATA wsd;
initial();
GetArgments(argc, argv);
/*初始化Winsock*/
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
printf("WSAStartup() failed\n");
return -1;
}
/*如果是执行广播程序*/
if (broadFlag)
{
/*以发送者身份发送消息*/
if (broadSendFlag)
{
broadcastSend();
return 0;
}
/*以接收者身份接收消息*/
else
{
broadcastRec();
return 0;
}
}
/*如果是执行多播程序*/
if (multiFlag)
{
/*以发送者身份发送消息*/
if (multiSendFlag)
{
multicastSend();
//return 0;
}
/*以接收者身份接收消息*/
else
{
multicastRec();
return 0;
}
}
return 0;
}
下一篇: 用PEAR来写你的PHP程序
推荐阅读
-
记录--js中出现的数组排序问题
-
mac下yarn安装vue-socket.io/node-gyp出现uws且卡住的问题解决办法
-
记录一次迁移环境 .env 出现的问题
-
Linux系统,无法收到组播消息的问题
-
EasyNVR实现网页/微信播放RTSP摄像机HLS直播时出现起播等待问题的优化过程
-
vue安装scss出现的问题记录+解决
-
[Ubuntu][记录]安装库出现的问题
-
mybatis-plus的selectById(或者selectOne)在根据主键ID查询实体对象的时候偶尔会出现null的问题记录
-
记录安装MySql出现的一个问题,和安装方法。
-
求组socket fsockopen 的有关问题