利用windows的SOCKET编写自己的UDP通信类

VS2015
win32控制台应用程序
我建的类名为MyUdpSocket,
MyUdpSocket.h头文件如下:

#pragma once
#include 
#include 
#include 
#include 
using namespace std;
class MyUdpSocket
{
public:
	MyUdpSocket();
	~MyUdpSocket();
	bool Initial(int nlocalPort, string strLocalIP, int nRemotePort, string strRemoteIP, bool bBlockMode = true);
	bool RecvData(std::vector& vReplay);
	bool SendData(std::vector& vSendData);
	void SetSocketSize(SOCKET sock,int nsize);
public:
	SOCKET					m_pcSocket;
	sockaddr_in				m_pcAddr;
	sockaddr_in				m_deviceCmdAddr;
};

MyUdpSocket.cpp源文件如下:

#include "stdafx.h"
#include "MyUdpSocket.h"
MyUdpSocket::MyUdpSocket()
{

}
MyUdpSocket::~MyUdpSocket()
{
}
bool MyUdpSocket::Initial(int nlocalPort, string strLocalIP, int nRemotePort, string strRemoteIP, bool bBlockMode)
{
	WSADATA wsaData0;
	if (0 == WSAStartup(MAKEWORD(2, 2), &wsaData0))
	{

		m_pcSocket = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
		unsigned long iMode = 0;
		if (!bBlockMode)
		{
			iMode = 1;
		}
		int nResult = ::ioctlsocket(m_pcSocket, FIONBIO, &iMode);//FIONBIO:允许或禁止套接口s的非阻塞模式。iMode:允许非阻塞模式则非零,如禁止非阻塞模式则为零
		if (m_pcSocket == INVALID_SOCKET)
		{
			printf("INVALID_SOCKET!");
		}
		m_pcAddr.sin_family = AF_INET;
		m_pcAddr.sin_port = ::htons((UINT)(nlocalPort));
		//m_pcAddr.sin_addr.S_un.S_addr = ::htonl(INADDR_ANY);
		m_pcAddr.sin_addr.S_un.S_addr = inet_addr(strLocalIP.c_str());
		int nRet = ::bind(m_pcSocket, (sockaddr*)&m_pcAddr, sizeof(sockaddr));
		if (nRet != 0)
		{
			printf("%s Socket bind failed!", strLocalIP.c_str());
			return false;
		}
		SetSocketSize(m_pcSocket,10);//设置SOCKET缓冲区大小,10表示10*8192字节
		m_deviceCmdAddr.sin_family = AF_INET;
		m_deviceCmdAddr.sin_port = ::htons(nRemotePort);
		m_deviceCmdAddr.sin_addr.S_un.S_addr = inet_addr(strRemoteIP.c_str());
	}
	return true;
}

bool MyUdpSocket::RecvData(std::vector& vReplay)
{
	sockaddr_in deviceAddr;
	int nAddrLen = sizeof(deviceAddr);
	int nDataLen = (int)vReplay.size();
	int nRet = ::recvfrom(m_pcSocket, (char*)&vReplay[0], nDataLen, 0, (SOCKADDR*)&deviceAddr, &nAddrLen);
	//int nRet = ::recvfrom(m_pcSocket, (char*)&vReplay[0], 568, 0, (SOCKADDR*)&deviceAddr, &nAddrLen);
	if (nRet > 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}

bool MyUdpSocket::SendData(std::vector& vSendData)
{
	char* ctemp = (char*)malloc(vSendData.size());
	memcpy(ctemp,&vSendData[0],vSendData.size());
	int nSendDataLen = (int)vSendData.size();
	int nResult = sendto(m_pcSocket, (char*)&vSendData[0], nSendDataLen, 0, (SOCKADDR*)&m_deviceCmdAddr, sizeof(SOCKADDR));
	if (nResult == nSendDataLen)
	{
		return true;
	}
	else
	{
		return false;
	}
}

void MyUdpSocket::SetSocketSize(SOCKET sock, int nsize)//设置缓冲区大小
{
	int nErrCode = 0;
	unsigned int uiRcvBuf = 0;
	unsigned int uiNewRecvBuf = 0;
	int uiRecvBufLen = sizeof(uiRcvBuf);
	nErrCode = getsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&uiRcvBuf,&uiRecvBufLen);
	if (SOCKET_ERROR == nErrCode)
	{
		printf("获取服务端设置SOCKET发送缓冲区大小失败");
		return;
	}
	uiRcvBuf = uiRcvBuf*nsize;//设置系统发送数据为默认的倍数
	nErrCode = setsockopt(sock,SOL_SOCKET,SO_SNDBUF,(char*)&uiRcvBuf,uiRecvBufLen);
	if (SOCKET_ERROR == nErrCode)
	{
		printf("设置SOCKET发送缓冲区大小失败");
		return;
	}
}

注意:在stdafx.h文件中需要添加如下代码:

#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
// 关闭对某些常见但经常可放心忽略的警告消息的隐藏

用法如下:
首先在头文件中包含该MyUdpSocket.h

#include "MyUdpSocket.h"

然后定义类对象,并调用初始化函数,设置本地及远端的端口和IP

MyUdpSocket   *m_socketRecvCommand = new MyUdpSocket;
m_socketRecvCommand->Initial(1111, "192.168.5.11", 1111, "192.168.5.10");//(本地端口,本地IP,远端设备端口,远端设备IP)

注意:该socket默认是阻塞式的,若想设置成非阻塞式则Initial时候需增加一个bool变量,如下:

m_socketRecvCommand->Initial(1111, "192.168.5.11", 1111, "192.168.5.10",false);

接数据:

std::vector vRecvCommand(512, 0);//定义一个512字节容量的vector容器vRecvCommand
m_socketRecvCommand->RecvData(vRecvCommand)//调用接收函数,若接到数据则数据存放在vRecvCommand中

发数据:

vector vSendData(nPacketLen, 0);
memcpy(&vSendData[0], &m_packetReCommand, nPacketLen);//m_packetReCommand是一个存放好需要发送数据的结构体
m_socketRecvCommand->SendData(vSendData);

你可能感兴趣的:(VS2015&C++控制台程序)