欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-29 18:54:40
...

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

    #pragma once
    #include <string>
    #include <vector>
    #include <winsock2.h>
    #include <iostream>
    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<char>& vReplay);
    	bool SendData(std::vector<char>& vSendData);
    public:
    	SOCKET					m_pcSocket;
    	sockaddr_in				m_pcAddr;
    	sockaddr_in				m_deviceCmdAddr;
    };

MyUdpSocket.h源文件如下:

  #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());
    		//绑定本地网口时,指定strLocalIP是为了 :1.从该网口接数据  2.发数据的时候从该网口出去(如果电脑有两个网口的话就必须绑定本地网口,如果只有一个网口的话可以用::htonl(INADDR_ANY)表示绑定任意网口)
    		int nRet = ::bind(m_pcSocket, (sockaddr*)&m_pcAddr, sizeof(sockaddr));
    		if (nRet != 0)
    		{
    			printf("%s Socket bind failed!", strLocalIP);
    			return false;
    		}
    		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<char>& vReplay)
    {
    	sockaddr_in deviceAddr;
    	int nAddrLen = sizeof(deviceAddr);
    	int nDataLen = 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<char>& vSendData)
    {
    	int nSendDataLen = 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;
    	}
    }

注意:在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<char> vRecvCommand(512, 0);//定义一个512字节容量的vector容器vRecvCommand
m_socketRecvCommand->RecvData(vRecvCommand)//调用接收函数,若接到数据则数据存放在vRecvCommand中

发数据:

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