内容:
利用数据报式套接字编写一个广播发送与接收程序。在局域网中实现广播。
服务端 (非广播)
加载socket服务 SOCKET server;
构建socket对象 server = socket(AF_INET,SOCK_DGRAM,0);
绑定 SOCKADDR_IN _addr;
_addr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
_addr.sin_family = AF_INET;
_addr.sin_port = htons(7000);
bind(server, (SOCKADDR*)&_addr, sizeof(_addr));
接收(同时得到对方的IP地址和端口号,供发送用)
SOCKADDR_IN _addr;
int fromlength = sizeof(from);
recvfrom(server,recv_buffer,strlen(recv_buffer), 0, (SOCKADDR*)&from, &fromlength));
发送 sendto(server,send_buffer,strlrn(send_buffer),0,(SOCKADDR*)&from, fromlength));
关闭socket、注销socket服务
shutdown(server, SD_BOTH);
closesocket(server);
客户端(非广播)
加载socket服务 、构建socket对象
SOCKET client = socket(AF_INET, SOCK_DGRAM, 0);
绑定(可选,无绑定时系统自动分配) 自动分配
发送,接收
SOCKADDR_IN server_addr; //服务器地址
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// 把标准的点分十进制的IP转换成长整形地址数据
server_addr.sin_port = htons(7000);
server_addr.sin_family = AF_INET;
int addrlen = sizeof(server_addr);
sendto(client,send_buffer,strlen(send_buffer),0,(SOCKADDR*)&server_addr, addrlen);
recvfrom(client,recv_buffer,strlen(recv_buffer),0,(SOCKADDR*)&server_addr,&addrlen);
关闭socket、注销socket服务
服务端 (广播)
//创建广播socket
SOCKET server = socket(AF_INET, SOCK_DGRAM, 0);
bool bBroadcast = true;
//设置为广播套接字
setsockopt(server, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(bool));
//设置 广播地址 端口
SOCKADDR_IN addr_bcast;
addr_bcast.sin_addr.S_un.S_addr = INADDR_BROADCAST;// ::inet_addr("255.255.255.255");
addr_bcast.sin_family = AF_INET;
addr_bcast.sin_port = htons(8000);
//发送广播
sendto(server, bcast_buffer, strlen(bcast_buffer), 0, (SOCKADDR*)&addr_bcast, sizeof(addr_bcast));
//注销socket省略。。。。。。。
客户端(广播)
//创建接收广播socket
SOCKET client = socket(AF_INET, SOCK_DGRAM, 0);
//设置接收广播本地 地址端口
sockaddr_in _addr;
_addr.sin_addr.S_un.S_addr = ADDR_ANY;
_addr.sin_port = htons(8000); //端口必须与广播端口保持一致
_addr.sin_family = AF_INET;
//绑定本地地址 对应端口
int err = bind(client, (SOCKADDR*)&_addr,sizeof(_addr));
if (err == SOCKET_ERROR)
{
printf("bind error\n");
return 0;
}
//接收广播
sockaddr_in bcast_from;
int sockaddr_len = sizeof(bcast_from);
char recv_buffer[512] = {0};
int recv_size = 0;
recv_size = recvfrom(client, recv_buffer, sizeof(recv_buffer), 0, (SOCKADDR*)&bcast_from, &sockaddr_len);
//注销socket省略。。。。。。。
代码实现
IDE :VS2015
服务器:
// ServerOrSendBroadcast.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#pragma comment(lib,"ws2_32.lib")
#include "InitSock.h"
#include "iostream"
#include "Windows.h"
#include "conio.h"
DWORD WINAPI ServerThread(LPVOID pParam);
DWORD WINAPI SendBroadcastThread(LPVOID pParam);
int main()
{
InitSock initSock;
int retCode = 0;
std::cout << "按ESCAPE退出程序\n";
DWORD threadID;
HANDLE hThread;
//hThread = CreateThread(NULL, 0, ServerThread, NULL, 0, &threadID); // 创建UDP服务器线程
hThread = CreateThread(NULL, 0, SendBroadcastThread, NULL, 0, &threadID); // 创建send广播线程
while (_getch() != 27);
return retCode;
}
DWORD WINAPI ServerThread(LPVOID pParam)
{
SOCKET server = socket(AF_INET,SOCK_DGRAM, 0);
SOCKADDR_IN _addr,from;
_addr.sin_addr.S_un.S_addr = htonl(ADDR_ANY);
_addr.sin_family = AF_INET;
_addr.sin_port = htons(7000);
bind(server, (SOCKADDR*)&_addr, sizeof(_addr));
std::cout<<"UDP服务器已经启动。。。\n";
char buffer[1024] = { 0 };
int fromlength = sizeof(from);
while (true)
{
int recvLen = recvfrom(server, buffer, sizeof(buffer), 0, (SOCKADDR*)&from, &fromlength);
if (recvLen>0)
{
printf("%s已经连上\r\n", inet_ntoa(from.sin_addr));
printf("%s\n",buffer);
char send_buffer[512] = {0};
sprintf(send_buffer, "%s\\n", "客户端你好!");
sendto(server,send_buffer,sizeof(send_buffer),0,(SOCKADDR*)&from,sizeof(from));
break;
}
}
shutdown(server, SD_BOTH);
closesocket(server);
return 0;
}
DWORD WINAPI SendBroadcastThread(LPVOID pParam)
{
SOCKET server = socket(AF_INET, SOCK_DGRAM, 0);
bool bBroadcast = true;
//设置广播
setsockopt(server, SOL_SOCKET, SO_BROADCAST, (char*)&bBroadcast, sizeof(bool));
SOCKADDR_IN addr_bcast;
addr_bcast.sin_addr.S_un.S_addr = INADDR_BROADCAST;// ::inet_addr("255.255.255.255");
addr_bcast.sin_family = AF_INET;
addr_bcast.sin_port = htons(8000);
printf("开始发送广播..\n");
char bcast_buffer[] = "this is a broadcast ~`";
for (int i = 0; i < 100; i++)
{
sendto(server, bcast_buffer, strlen(bcast_buffer), 0, (SOCKADDR*)&addr_bcast, sizeof(addr_bcast));
printf("%d: %s\n", i+1,bcast_buffer);
Sleep(1000);
}
shutdown(server, SD_BOTH);
closesocket(server);
return 0;
}
客户端:
// UDP_ClientOrBroadcastReceiver.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include "InitSock.h"
#include "iostream"
#include "Windows.h"
#include "conio.h"
#pragma comment(lib,"ws2_32.lib")
DWORD WINAPI ClientThread(LPVOID pParam);
DWORD WINAPI ReceiveBroadcastThread(LPVOID pParam);
int main()
{
CInitSock initSock;
Sleep(5000);
int retCode = 0;
std::cout << "按ESCAPE退出程序\n";
DWORD threadID;
HANDLE hThread;
//hThread = CreateThread(NULL, 0, ClientThread, NULL, 0, &threadID); // 创建UDP client线程
hThread = CreateThread(NULL, 0, ReceiveBroadcastThread, NULL, 0, &threadID); // 创建接收广播线程
while (_getch() != 27);
return retCode;
return 0;
}
DWORD WINAPI ClientThread(LPVOID pParam)
{
SOCKADDR_IN server_addr;
server_addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(7000);
server_addr.sin_family = AF_INET;
int addrlen = sizeof(server_addr);
SOCKET client = socket(AF_INET, SOCK_DGRAM, 0);
printf("UDP客户端已经启动\r\n");
char buffer[] = "服务器,你好!\r\n ";
if (0 != sendto(client, buffer, sizeof(buffer), 0, (SOCKADDR*)&server_addr, sizeof(server_addr)))
{
::recvfrom(client, buffer, 10, 0, (sockaddr*)&server_addr, &addrlen);
printf("服务器说:%s\r\n", buffer);
}
shutdown(client, SD_BOTH);
closesocket(client);
return 0;
}
DWORD WINAPI ReceiveBroadcastThread(LPVOID pParam)
{
SOCKET client = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in _addr;
_addr.sin_addr.S_un.S_addr = ADDR_ANY;
_addr.sin_port = htons(8000);
_addr.sin_family = AF_INET;
sockaddr_in bcast_from;
int sockaddr_len = sizeof(bcast_from);
int err = bind(client, (SOCKADDR*)&_addr,sizeof(_addr));
if (err == SOCKET_ERROR)
{
printf("bind error\n");
return 0;
}
printf("准备接收广播。。。\n");
char recv_buffer[512] = {0};
int recv_size = 0;
//接收数据
recv_size = recvfrom(client, recv_buffer, sizeof(recv_buffer), 0, (SOCKADDR*)&bcast_from, &sockaddr_len);
if (recv_size<=0)
{
printf("receive error\n");
}
while (recv_size >0)
{
recv_buffer[recv_size] = '\0';
printf("收到广播:%s from:%s:%d\n", recv_buffer,inet_ntoa(bcast_from.sin_addr),(bcast_from.sin_port));
memset(recv_buffer, 0, strlen(recv_buffer));
recv_size = 0;
recv_size = recvfrom(client, recv_buffer, sizeof(recv_buffer), 0, (SOCKADDR*)&bcast_from, &sockaddr_len);
}
shutdown(client, SD_BOTH);
closesocket(client);
return 0;
}
结果
简单UDP通信
UDP广播通信
总结
在进行UDP广播测试时广播发送的地址端口与接收广播地址端口保持一致。