UDP单播

服务端

#define  _WINSOCK_DEPRECATED_NO_WARNINGS
#define  _CRT_SECURE_NO_WARNINGS

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <iostream>
#include <conio.h>
#include <stdlib.h>
#include <algorithm>
#include <set>
using namespace  std;
#pragma comment(lib,"ws2_32.lib")
#define SERVERPORT 6666
set<SOCKADDR_IN*> clientSockAddrInSet;
SOCKET serverSocket;
void SendMsg()
{

	SOCKET tempSocket = socket(AF_INET, SOCK_DGRAM, 0);
	while (1)
	{
		//		'+' 43
		//		'/'	47
		//		'*' 42
		char key = _getch();
		if (key == '+')		//发送消息
		{
			int sendtoRet = 0;
			printf("【*】群发【/】单发\n");
			key = _getch();
			printf("发送内容:");
			char sendStr[100] = {};
			gets_s(sendStr, sizeof(sendStr));
			if (key == '*')	//群发
			{
				for (auto clientSockAddr : clientSockAddrInSet)
				{
					sendtoRet = sendto(serverSocket, sendStr, strlen(sendStr), 0, (sockaddr*)clientSockAddr, sizeof(SOCKADDR_IN));
				}
			}
			else if (key == '/')		//单发
			{
				printf("客户端端口号:");
				int hostPort = 0;		//主机端口号(小端形式)
				char temp[100] = {};
				gets_s((char*)&temp, sizeof(temp));
				sscanf(temp, "%d", &hostPort);
				set<SOCKADDR_IN*>::iterator iter;
				iter = find_if(clientSockAddrInSet.begin(), clientSockAddrInSet.end(), [hostPort](set<SOCKADDR_IN*>::value_type temp)
				{
					return ntohs(temp->sin_port)  == hostPort;
				});		
				if (iter != clientSockAddrInSet.end())
				{
					/*************注意*********/
					//如果客户端是通过connect方式连接的服务端,那么服务端给客户端发送数据的时候,sendto的第一个参数套接字必须要和主机IP+Port绑定
					//非连接的方式,任意一个Socket都OK(当然协议要正确)
					//sendtoRet = sendto(tempSocket, sendStr, strlen(sendStr), 0, (SOCKADDR*)(*iter), sizeof(SOCKADDR_IN));
					/**************************/			
					sendtoRet = sendto(serverSocket, sendStr, strlen(sendStr), 0, (SOCKADDR*)(*iter), sizeof(SOCKADDR_IN));
				}
				else
				{
					printf("输入端口号有误\n");
					continue;
				}
			}
			if (sendtoRet != 0)
				printf("已发送%dbyte\n", sendtoRet);
			else
				printf("发送失败\n");
		}
	}
	
}

int main()
{
	WSADATA wsaData = { 0 };
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	serverSocket = socket(AF_INET, SOCK_DGRAM, 0);
	SOCKADDR_IN sockaddr_in = { 0 };
	sockaddr_in.sin_family = AF_INET;
	sockaddr_in.sin_addr.S_un.S_addr = INADDR_ANY; //inet_addr("127.0.0.1");		//接收任意ip+指定端口连入
	sockaddr_in.sin_port = htons(SERVERPORT);					
	 int bindRet = bind(serverSocket, (sockaddr*)&sockaddr_in, sizeof(sockaddr_in));
	if(bindRet == SOCKET_ERROR)
	{
		cout << "绑定失败\n";
		closesocket(serverSocket);
		WSACleanup();
		system("pause");
		return 0;
	}
	cout << "准备好了\n";
	CreateThread(0, 0, (LPTHREAD_START_ROUTINE)SendMsg, 0, 0, 0);	//准备发送消息线程
	while(true)
	{
		SOCKADDR_IN clientSockAddr_in = {0};
		int clientSockAddrLen = sizeof(SOCKADDR_IN);
		char recvStr[100] = { 0 };
		int recvfromRet = recvfrom(serverSocket, recvStr, sizeof(recvStr), 0, (SOCKADDR*)&clientSockAddr_in,&clientSockAddrLen);		
		if (recvfromRet != SOCKET_ERROR)
			printf("客户端(%s:%d):%s\n", inet_ntoa(clientSockAddr_in.sin_addr), ntohs(clientSockAddr_in.sin_port) , recvStr);
		set<SOCKADDR_IN*>::iterator iter;
		//新的客户端接入
		iter =find_if(clientSockAddrInSet.begin(), clientSockAddrInSet.end(), [clientSockAddr_in](set<SOCKADDR_IN*>::value_type temp)
		{
			return temp->sin_port == clientSockAddr_in.sin_port;
		});
		if (iter == clientSockAddrInSet.end())
		{
			SOCKADDR_IN* temp = new SOCKADDR_IN{ 0 };
			*temp = clientSockAddr_in;
			clientSockAddrInSet.insert(temp);
		}
		
	}

}

客户端

#define  _WINSOCK_DEPRECATED_NO_WARNINGS

#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <iostream>
using namespace  std;
#pragma comment(lib,"ws2_32.lib")
#define SERVERPORT 6666
#define SERVERIP "172.16.20.203"
//#define SERVERIP "192.168.74.255"123
#define PRINTIPPORT(clientSocket) 			\
{ 	SOCKADDR_IN sockaddrTemp = { 0 };		\
	int sockaddrTempLen = sizeof(sockaddrTemp);		\
	getsockname(clientSocket, (SOCKADDR*)&sockaddrTemp, &sockaddrTempLen);		\
	cout << inet_ntoa(sockaddrTemp.sin_addr) << ":" << ntohs(sockaddrTemp.sin_port) << endl;		\
}

void RecvMsg(SOCKET* socket)
{
	while (true)
	{
		char recvStr[100] = { 0 };
		SOCKADDR_IN sockaddr_in = {0};
		int len = sizeof(sockaddr);
		int recvRet =	recvfrom(*socket, recvStr, sizeof(recvStr), 0, (sockaddr*)&sockaddr_in,&len);
		if (recvRet != SOCKET_ERROR)
			printf("服务端(%s:%d):%s\n", inet_ntoa(sockaddr_in.sin_addr), ntohs(sockaddr_in.sin_port), recvStr);
		else
			break;
	}
}

int main()
{
	WSADATA wsaData = { 0 };
	WSAStartup(MAKEWORD(2, 2), &wsaData);
	SOCKET clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
	//******bind自定义端口号测试*********/
	//SOCKADDR_IN clientSockAddr_in = { 0 };
	//clientSockAddr_in.sin_family = AF_INET;
	//clientSockAddr_in.sin_addr.S_un.S_addr = INADDR_ANY;
	//clientSockAddr_in.sin_port = htons(2222);	
	//if (bind(clientSocket, (SOCKADDR*)&clientSockAddr_in, sizeof(clientSockAddr_in)) == SOCKET_ERROR)
	//{
	//	cout << "绑定套接字失败\n";
	//	closesocket(clientSocket);
	//	WSACleanup();
	//	system("pause");
	//	return 0;
	//}
	/***************************************/
	SOCKADDR_IN sockaddr_in = { 0 };
	sockaddr_in.sin_family = AF_INET;
	sockaddr_in.sin_addr.S_un.S_addr = inet_addr(SERVERIP);
	sockaddr_in.sin_port = htons(SERVERPORT);
	//打印当前客户端使用的IP+Port
	PRINTIPPORT(clientSocket)
	//UDP的connect函数不用在服务端启动之后调用(客户端根本不关心服务端在不在,它只要让本地套接字知道了目的地址罢了)
	int connectRet = connect(clientSocket, (sockaddr*)&sockaddr_in, sizeof(sockaddr_in));
	if(connectRet == SOCKET_ERROR)
	{
		cout << "连接失败\n";
		closesocket(clientSocket); 
		WSACleanup();
		system("pause");
		return 0;
	}
	//打印当前客户端使用的IP+Port
	PRINTIPPORT(clientSocket)

	
	while(true)
	{
		cout << "输入信息:";
		char sendStr[100] = { 0 };
		gets_s(sendStr, sizeof(sendStr));
		//int sendtoRet = sendto(clientSocket, sendStr, strlen(sendStr), 0, (sockaddr*)&sockaddr_in, sizeof(sockaddr_in));	//sendto之后socket和ip+port系统进行绑定
		int sendtoRet = sendto(clientSocket, sendStr, strlen(sendStr), 0, 0,0);		//使用了connect方式,sockaddr_in 参数不需要了
		if (sendtoRet != SOCKET_ERROR)
			cout << "发送" << sendtoRet << "byte\n";
		
		//接收一个服务端
		static int flag = 0;
		if (flag == 0)
		{
			flag = 1;
			CreateThread(0, 0, (LPTHREAD_START_ROUTINE)RecvMsg, &clientSocket, 0, 0);		//必须在和服务端通信过之后才能接收消息(通信一次之后)
		}
		//打印当前客户端使用的IP+Port
		PRINTIPPORT(clientSocket)
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值