数据报套接字程序设计

原创
2017/06/10 18:13
阅读数 374

内容

利用数据报式套接字编写一个广播发送与接收程序。在局域网中实现广播。

服务端 (非广播)

加载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广播测试时广播发送的地址端口与接收广播地址端口保持一致。

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部