Win32 SOCKET之UDP

Socket.h
#ifndef __SOCKET_H__
#define __SOCKET_H__

#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

#pragma warning(disable : 4786) 

#include <errno.h>
#include <vector>
using namespace std;

// select mode 
#define SELECT_MODE_READY   0x001
#define SELECT_MODE_WRITE	0x002

// select return codes 
#define SELECT_STATE_READY         0
#define SELECT_STATE_ERROR         1
#define SELECT_STATE_ABORTED       2
#define SELECT_STATE_TIMEOUT       3

class Socket
{
public:
	Socket(UINT mtu = 1500);
	virtual ~Socket();

	virtual void Close();

	virtual int Write(PBYTE pBuffer, int writeSize, UINT nTimeOut = 500000);  // 0.5sec
	virtual int Read(BYTE* pBuffer, int readSize, UINT nTimeOut = 500000); // 0.5sec

	virtual SOCKADDR_IN GetBindAddr();
	virtual SOCKADDR_IN GetConnectAddr();

	virtual	UINT GetMTU();

	static BOOL GetLocalIPList(vector<string>& vIPList);
	static BOOL GetAdapterSpeed(vector<int>& vList);

protected:
	void	ReportError();
	int		Select(int mode, int timeoutUsec);

	BOOL	m_isOpen;

	SOCKET		m_Socket;
	SOCKADDR_IN m_BindAddr;
	SOCKADDR_IN m_ConnectAddr;

	UINT	m_Mtu;
};

#endif //__SOCKET_H__


Socket.cpp

#include "stdafx.h"
#include "Socket.h"

Socket::Socket(UINT mtu)
:m_Mtu(mtu)
{
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD( 2, 2 );
	WSAStartup(wVersionRequested, &wsaData);

	m_Socket = NULL;
	memset(&m_BindAddr, 0, sizeof(m_BindAddr));
	memset(&m_ConnectAddr, 0, sizeof(m_ConnectAddr));

	m_isOpen = FALSE;
}

Socket::~Socket()
{
	Close();

	WSACleanup();
}

void Socket::Close()
{
	if (m_Socket)
		closesocket(m_Socket);
	m_Socket = NULL;

	m_isOpen = FALSE;
}

int Socket::Read(BYTE* pBuffer, int readSize, UINT nTimeOut)
{
	int selectState;
	int recvSize;

	if (!pBuffer || !m_isOpen)
		return -1;

	selectState = Select(SELECT_MODE_READY, nTimeOut);
	if (SELECT_STATE_TIMEOUT == selectState)
		 return 0;
	if (SELECT_STATE_READY == selectState)
	{
		recvSize = recv(m_Socket, (char*)pBuffer, readSize, 0);
		if (recvSize <= 0)
			return -1;
		return recvSize;
	}
	return -1;
}

int Socket::Write(PBYTE pBuffer, int writeSize, UINT nTimeOut)
{
	int selectState = 0;
	int sendSize = 0;

	if (!pBuffer || !m_isOpen)
		return -1;

	selectState = Select(SELECT_MODE_WRITE, nTimeOut);
	if (selectState == SELECT_STATE_TIMEOUT)
		return 0;

	if (selectState == SELECT_STATE_READY)
	{
		sendSize = send(m_Socket, (char*)pBuffer, writeSize, 0);
		if (sendSize <= 0)
			return -1;
		return sendSize;
	}	

	return -1;
}

SOCKADDR_IN Socket::GetBindAddr()
{
	return m_BindAddr;
}

SOCKADDR_IN Socket::GetConnectAddr()
{
	return m_ConnectAddr;
}

UINT Socket::GetMTU()
{
	return m_Mtu;
}


//  Waits for a file descriptor/socket to change status.
// 
//  network input plugins should use this function in order to
//  not freeze the engine.
// 
//  params :
//    mode           SELECT_MODE_READY, SELECT_MODE_WRITE
//    timeout_usec   timeout in microsecond
// 
//  return value :
//    SELECT_STATE_READY     the file descriptor is ready for cmd
//    SELECT_STATE_ERROR     an i/o error occured
//    SELECT_STATE_ABORTED   command aborted by an other thread
//    SELECT_STATE_TIMEOUT   the file descriptor is not ready after timeout_usec microsecond

int Socket::Select(int mode, int timeoutUsec) 
{
	fd_set fdset;
	fd_set *readSet, *writeSet;
	timeval selectTimeout;
	int ret;

	selectTimeout.tv_sec  = 0;
	selectTimeout.tv_usec = timeoutUsec;

	FD_ZERO (&fdset);
	FD_SET  (m_Socket, &fdset);

	readSet = (mode & SELECT_MODE_READY) ? &fdset : NULL;
	writeSet = (mode & SELECT_MODE_WRITE) ? &fdset : NULL;

	ret = select ( (int)m_Socket + 1, readSet, writeSet, NULL, &selectTimeout);

	if (ret == 1) 
		return SELECT_STATE_READY;

	if (ret == SOCKET_ERROR) 
	{
		if ( errno == EINTR)
			return SELECT_STATE_ABORTED;

		ReportError();
		return SELECT_STATE_ERROR;
	} 

	return SELECT_STATE_TIMEOUT;
}

void Socket::ReportError()
{
	int isErr = WSAGetLastError();
	printf("Socket error is:%d\n", isErr);

	//Close();
}

BOOL Socket::GetLocalIPList(vector<string>& vIPList)
{ 
	WORD wVersionRequested; 
	WSADATA wsaData; 
	int err; 
	
	wVersionRequested = MAKEWORD( 2, 2 ); 
	err = WSAStartup( wVersionRequested, &wsaData ); 
	if ( err != 0 ) 
	{
		printf("GetLocalIPList	: WSAStartup failed !"); 
		return FALSE; 
	} 

	char szhn[256]; 
	int nStatus = gethostname(szhn, sizeof(szhn)); 
	if (nStatus == SOCKET_ERROR ) 
	{ 
		printf("Socket	: Gethostname failed, Error code: %d", WSAGetLastError()); 
		return FALSE; 
	} 
	
	HOSTENT *host = gethostbyname(szhn); 
	if (host != NULL) 
	{ 
		for ( int i=0; ; i++ ) 
		{ 
			vIPList.push_back( inet_ntoa( *(IN_ADDR*)host->h_addr_list[i] ) ) ; 
			if ( host->h_addr_list[i] + host->h_length >= host->h_name ) 
				break; 
		}
	}
		
	WSACleanup(); 

	return TRUE; 
}

Udp.h

#ifndef __UDP_H__
#define __UDP_H__

#include "Socket.h"
#include <WS2tcpip.h>

#include <string>
using namespace std;

class Udp : public Socket
{
public:

	Udp(UINT mtu = 1500);
	virtual ~Udp();

	virtual BOOL Open(string bindIp = "", int bindPort = 0);

	virtual BOOL Connect(string connectIp, int connectPort);

	virtual int  Read(BYTE* pBuffer, UINT16 bufferSize, UINT nTimeOut = 500000);

	virtual int  Write(PBYTE pBuffer, UINT16 bufferSize, UINT nTimeOut = 500000);

protected:

	BOOL SetMulticast(PCSTR textIP);

	BOOL	m_isConnect;
};

#endif //__UDP_H__


Udp.cpp

#include "stdafx.h"

#include "Udp.h"

Udp::Udp(UINT mtu) :Socket(mtu)
{
	m_isConnect = FALSE;
}

Udp::~Udp()
{
}

BOOL Udp::Open(string bindIp, int bindPort)
{
	if (m_isOpen)
		return FALSE;

	m_isOpen = FALSE;
	m_isConnect = FALSE;

	int error = 0;
	int i_val = 0;
	
	if (m_Socket)
		closesocket(m_Socket);
	m_Socket= socket(AF_INET, SOCK_DGRAM, 0);
	if ( m_Socket == INVALID_SOCKET )
	{
		ReportError();
		return FALSE;
	}

	i_val = 0;	// 非阻塞方式
	error = ioctlsocket(m_Socket, FIONBIO, (ULONG*)&i_val);
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}

	i_val = (int)(1024 * 1024 * 1.25);//2M Byte 1000Mbps的network在0.01秒内最高可以接收到1.25MB数据
	error = setsockopt( m_Socket, SOL_SOCKET, SO_RCVBUF, (char*)&i_val, sizeof(i_val) );
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}

	error = setsockopt( m_Socket, SOL_SOCKET, SO_SNDBUF, (char*)&i_val, sizeof(i_val) );
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}	

	// 可重用
	i_val = 1;
	error = setsockopt(m_Socket, SOL_SOCKET, SO_REUSEADDR, (char*)&i_val, sizeof(i_val));
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}

	// 设置ttl
	i_val = 5;
	error = setsockopt(m_Socket,IPPROTO_IP,IP_MULTICAST_TTL,(char*)&i_val, sizeof(i_val));
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}
	
	// 绑定套接字
	memset((PVOID)&m_BindAddr, 0, sizeof(m_BindAddr));

	m_BindAddr.sin_family = AF_INET;   
	m_BindAddr.sin_port = htons(bindPort);
	m_BindAddr.sin_addr.s_addr = inet_addr(bindIp.c_str());
	
	if ( IN_MULTICAST(ntohl(m_BindAddr.sin_addr.s_addr))  || m_BindAddr.sin_addr.s_addr == INADDR_BROADCAST )
		m_BindAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	error = bind(m_Socket, (SOCKADDR*)&m_BindAddr, sizeof(m_BindAddr));
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}
	
	i_val = sizeof(m_BindAddr);
	error = getsockname(m_Socket, (SOCKADDR*)&m_BindAddr, &i_val);
	if (error == SOCKET_ERROR)
	{
		ReportError();
		return FALSE;
	}

	if ( ! SetMulticast(bindIp.c_str()))
		return FALSE;

	m_isOpen = TRUE;
	return TRUE;
}

BOOL Udp::Connect(string connectIp, int connectPort)
{
	if (!m_isOpen)
		return FALSE;

	int error = 0;
	int i_val = 0;

	memset((PVOID)&m_ConnectAddr, 0, sizeof(m_ConnectAddr));

	if ( ! SetMulticast(connectIp.c_str()))
		return FALSE;

	m_ConnectAddr.sin_family = AF_INET;
	m_ConnectAddr.sin_port = htons(connectPort);
	m_ConnectAddr.sin_addr.s_addr = inet_addr(connectIp.c_str());

	if (connect(m_Socket, (SOCKADDR*)&m_ConnectAddr, sizeof(m_ConnectAddr)) == SOCKET_ERROR )
	{
		ReportError();
		return FALSE;
	}
	m_isConnect = TRUE;
	return TRUE;
}

int Udp::Read(BYTE* pBuffer, UINT16 bufferSize, UINT nTimeOut)
{
	int iRead;

	if ( !m_isOpen )
		return -1;
	
	iRead = Socket::Read(pBuffer, bufferSize, nTimeOut);

	return iRead;
}

int Udp::Write(PBYTE pBuffer, UINT16 bufferSize, UINT nTimeOut)
{
	int iWrite;

	if ( !m_isOpen || !m_isConnect)
		return -1;

	iWrite = Socket::Write(pBuffer, bufferSize, nTimeOut);

	return iWrite;
}


BOOL Udp::SetMulticast(PCSTR textIP)
{
	int error = 0;
	int i_val = 0;

	// 设置多播和广播
	if ( IN_MULTICAST(ntohl(inet_addr(textIP))) )
	{
		i_val = 1;
		error =  setsockopt(m_Socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char*)&i_val, sizeof(i_val) );
		if (error == SOCKET_ERROR)
		{
			ReportError();
			return FALSE;
		}
		
		ip_mreq multicastAddr;
		multicastAddr.imr_multiaddr.s_addr = inet_addr(textIP);
		multicastAddr.imr_interface.s_addr = htonl(INADDR_ANY);
		
		error = setsockopt(m_Socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&multicastAddr, sizeof(multicastAddr));
		if (error == SOCKET_ERROR)
		{
			ReportError();
			return FALSE;
		}
	}
	
	//设置广播
	if ( inet_addr(textIP) == INADDR_BROADCAST )
	{
		i_val = 1;
		error = setsockopt( m_Socket, SOL_SOCKET, SO_BROADCAST, (char*)&i_val, sizeof(i_val) );
		if (error == SOCKET_ERROR)
		{
			ReportError();
			return FALSE;
		}
	}
	return TRUE;}

main.cpp

#include "Udp.h"
#include <process.h>
#include <iostream>
UINT CALLBACK RecvData(LPVOID arg)
{
	Udp recv;
	if(FALSE == recv.Open("192.168.1.10",2017))
	{
		std::cout << "Can not open Udp" << std::endl;
		return 0;
	}
	char dataBuf[100];
	while(1)
	{
		memset(dataBuf,'\0',100);
		PBYTE pTemp = (PBYTE)dataBuf;
		int nLen = sizeof(dataBuf);
		int nRead = -1;
		while(nLen > 0)
		{
			nRead = recv.Read(pTemp,nLen,1000000);
			if(nRead == SOCKET_ERROR || nRead == 0) break;
			pTemp += nRead;
			nLen  -= nRead;
		}
		if(nLen == 0)
		{
			//
			std::cout << "GetData: " << dataBuf << std::endl;
		}
	}
	return 0;
}
int main()
{
	UINT tid;
	HANDLE hThread = (HANDLE)_beginthreadex(NULL,0,RecvData,NULL,0,&tid);
	Udp send;
	send.Open();
	if(FALSE == send.Connect("192.168.1.10",2017))
		std::cout << "Can not connect Udp" << std::endl;
	
	char* dataBuf = "abcdefghijklmnopqrstuvwxyz";
	PBYTE pTemp = (PBYTE)dataBuf;
	int nLen = strlen(dataBuf);
	int nWrite = -1;
	while(nLen > 0)
	{
		nWrite = send.Write(pTemp,nLen);
		if(nWrite == SOCKET_ERROR || nWrite == 0) break;
		pTemp += nWrite;
		nLen  -= nWrite;
	}
	system("pause");
	CloseHandle(hThread);
	return 0;
}


 
 
 
 
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/HHCOO/article/details/76209400
今日推荐