化繁为简系列原创教程 - 通信专题 - C++套接字类CxUdpSocket的设计
添加时间:2013-7-19 点击量:
这是一个小巧的C++套接字类,类名、函数名和变量名均采取匈牙利定名法。小写的x代表我的姓氏首字母(谢欣能),小我习惯罢了,如有类似,纯属偶合。
CxUdpSocket的定义如下:
class XIOCTRL_CLASS CxUdpSocket : public CxSocket
{
public:
CxUdpSocket();
virtual ~CxUdpSocket();
void operator=(SOCKET s) { m_socket = s; }
public:
BOOL Bind(int nPort);
BOOL Disbind();
BOOL IsBinded();
BOOL SendTo(LPCSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize);
BOOL RecvFrom(LPSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize);
protected:
int m_nPort;
};
因为这个类被封装在动态库里面,所以类名前应用了导出标记XIOCTRL_CLASS,读者在应用时完全可以去掉。类的定义被放在一个包含很多类定义的头文件中,没有零丁为它写头文件,所以它的定义项目组代码看上去没有高低文。
CxUdpSocket的实现如下:
CxUdpSocket::CxUdpSocket()
: m_nPort(0)
{
}
CxUdpSocket::~CxUdpSocket()
{
}
BOOL CxUdpSocket::Bind(int nPort)
{
Disbind();
if (m_socket == INVALID_SOCKET)
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (m_socket == INVALID_SOCKET)
return FALSE;
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(nPort);
int iRet = bind(m_socket, (SOCKADDR)&addr, sizeof(addr));
if (iRet == SOCKET_ERROR)
{
Disbind();
DWORD dwError = WSAGetLastError();
return FALSE;
}
long lEvent = FD_WRITE | FD_READ | FD_CLOSE;
SelectEvent(lEvent);
m_nPort = nPort;
return TRUE;
}
BOOL CxUdpSocket::IsBinded()
{
sockaddr_in saCur = {0};
int nLen = sizeof(saCur);
int iResult = getsockname(m_socket, (SOCKADDR)&saCur, &nLen);
return (iResult != SOCKET_ERROR);
}
BOOL CxUdpSocket::SendTo(LPCSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize)
{
if (m_socket == INVALID_SOCKET)
return FALSE;
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(lpszIPAddr);
addr.sin_port = htons(m_nPort);
DWORD nMaxSize = MAX_MSG_SIZE, nCount = 0, nToSend;
int iRet;
LPBYTE lpbtIterator;
while (nCount != dwSize)
{
nToSend = min((dwSize - nCount), nMaxSize);
lpbtIterator = &lpbtData[nCount];
iRet = sendto(m_socket, (const char)lpbtIterator, nToSend, 0,
(SOCKADDR)&addr, sizeof(addr));
if (iRet > 0)
nCount += iRet;
else
break;
}
return (nCount == dwSize);
}
BOOL CxUdpSocket::RecvFrom(LPSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize)
{
if (m_socket == INVALID_SOCKET)
return FALSE;
sockaddr_in addrRemote = {0};
int nSize = sizeof(addrRemote);
DWORD nMaxSize = MAX_MSG_SIZE;
DWORD nCount = 0;
DWORD nToReceive;
int iRet;
LPBYTE lpbtIterator;
while (nCount != dwSize)
{
nToReceive = min((dwSize - nCount), nMaxSize);
lpbtIterator = &lpbtData[nCount];
iRet = recv(m_socket, (char)lpbtIterator, nToReceive, 0,
(SOCKADDR)&addrRemote, &nSize);
if (iRet > 0)
nCount += iRet;
else
break;
}
strcpy(lpszIPAddr, inet_ntoa(addrRemote.sin_addr));
return (nCount == dwSize);
}
BOOL CxUdpSocket::Disbind()
{
if (m_socket == INVALID_SOCKET)
return TRUE;
int nRet = closesocket(m_socket);
if (nRet == SOCKET_ERROR)
return FALSE;
m_socket = INVALID_SOCKET;
m_nPort = 0;
return TRUE;
}
类的实现被放在一个包含很多类实现的CPP文件中,没有零丁为它写CPP文件,所以它的实现项目组代码看上去没有高低文(比如头文件包含、宏定义等等)。MAX_MSG_SIZE是一个定义为1024的宏,来自对另一个头文件的引用(将来的文章会向大师介绍)。这个类的实现项目组的代码不久不多,统共120多行。实现了(解)绑定地址与端口、发送接管数据以及侦听接管数据的功能(仅以消息响应的体式格式通知上层法度处理惩罚接管数据)。
我写的很多实用类都很是简洁,一般都没有注释,有也是中英文混搭两句,大师习惯就好。To be continued...
文艺不是炫耀,不是花哨空洞的文字堆砌,不是一张又一张的逆光照片,不是将旅行的意义转化为名牌包和明信片的物质展示;很多时候它甚至完全不美——它嘶吼、扭曲,它会痛苦地抽搐,它常常无言地沉默。——艾小柯《文艺是一种信仰》
这是一个小巧的C++套接字类,类名、函数名和变量名均采取匈牙利定名法。小写的x代表我的姓氏首字母(谢欣能),小我习惯罢了,如有类似,纯属偶合。
CxUdpSocket的定义如下:
class XIOCTRL_CLASS CxUdpSocket : public CxSocket
{
public:
CxUdpSocket();
virtual ~CxUdpSocket();
void operator=(SOCKET s) { m_socket = s; }
public:
BOOL Bind(int nPort);
BOOL Disbind();
BOOL IsBinded();
BOOL SendTo(LPCSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize);
BOOL RecvFrom(LPSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize);
protected:
int m_nPort;
};
因为这个类被封装在动态库里面,所以类名前应用了导出标记XIOCTRL_CLASS,读者在应用时完全可以去掉。类的定义被放在一个包含很多类定义的头文件中,没有零丁为它写头文件,所以它的定义项目组代码看上去没有高低文。
CxUdpSocket的实现如下:
CxUdpSocket::CxUdpSocket()
: m_nPort(0)
{
}
CxUdpSocket::~CxUdpSocket()
{
}
BOOL CxUdpSocket::Bind(int nPort)
{
Disbind();
if (m_socket == INVALID_SOCKET)
m_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (m_socket == INVALID_SOCKET)
return FALSE;
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(nPort);
int iRet = bind(m_socket, (SOCKADDR)&addr, sizeof(addr));
if (iRet == SOCKET_ERROR)
{
Disbind();
DWORD dwError = WSAGetLastError();
return FALSE;
}
long lEvent = FD_WRITE | FD_READ | FD_CLOSE;
SelectEvent(lEvent);
m_nPort = nPort;
return TRUE;
}
BOOL CxUdpSocket::IsBinded()
{
sockaddr_in saCur = {0};
int nLen = sizeof(saCur);
int iResult = getsockname(m_socket, (SOCKADDR)&saCur, &nLen);
return (iResult != SOCKET_ERROR);
}
BOOL CxUdpSocket::SendTo(LPCSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize)
{
if (m_socket == INVALID_SOCKET)
return FALSE;
sockaddr_in addr = {0};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(lpszIPAddr);
addr.sin_port = htons(m_nPort);
DWORD nMaxSize = MAX_MSG_SIZE, nCount = 0, nToSend;
int iRet;
LPBYTE lpbtIterator;
while (nCount != dwSize)
{
nToSend = min((dwSize - nCount), nMaxSize);
lpbtIterator = &lpbtData[nCount];
iRet = sendto(m_socket, (const char)lpbtIterator, nToSend, 0,
(SOCKADDR)&addr, sizeof(addr));
if (iRet > 0)
nCount += iRet;
else
break;
}
return (nCount == dwSize);
}
BOOL CxUdpSocket::RecvFrom(LPSTR lpszIPAddr, LPBYTE lpbtData, DWORD dwSize)
{
if (m_socket == INVALID_SOCKET)
return FALSE;
sockaddr_in addrRemote = {0};
int nSize = sizeof(addrRemote);
DWORD nMaxSize = MAX_MSG_SIZE;
DWORD nCount = 0;
DWORD nToReceive;
int iRet;
LPBYTE lpbtIterator;
while (nCount != dwSize)
{
nToReceive = min((dwSize - nCount), nMaxSize);
lpbtIterator = &lpbtData[nCount];
iRet = recv(m_socket, (char)lpbtIterator, nToReceive, 0,
(SOCKADDR)&addrRemote, &nSize);
if (iRet > 0)
nCount += iRet;
else
break;
}
strcpy(lpszIPAddr, inet_ntoa(addrRemote.sin_addr));
return (nCount == dwSize);
}
BOOL CxUdpSocket::Disbind()
{
if (m_socket == INVALID_SOCKET)
return TRUE;
int nRet = closesocket(m_socket);
if (nRet == SOCKET_ERROR)
return FALSE;
m_socket = INVALID_SOCKET;
m_nPort = 0;
return TRUE;
}
类的实现被放在一个包含很多类实现的CPP文件中,没有零丁为它写CPP文件,所以它的实现项目组代码看上去没有高低文(比如头文件包含、宏定义等等)。MAX_MSG_SIZE是一个定义为1024的宏,来自对另一个头文件的引用(将来的文章会向大师介绍)。这个类的实现项目组的代码不久不多,统共120多行。实现了(解)绑定地址与端口、发送接管数据以及侦听接管数据的功能(仅以消息响应的体式格式通知上层法度处理惩罚接管数据)。
我写的很多实用类都很是简洁,一般都没有注释,有也是中英文混搭两句,大师习惯就好。To be continued...
文艺不是炫耀,不是花哨空洞的文字堆砌,不是一张又一张的逆光照片,不是将旅行的意义转化为名牌包和明信片的物质展示;很多时候它甚至完全不美——它嘶吼、扭曲,它会痛苦地抽搐,它常常无言地沉默。——艾小柯《文艺是一种信仰》