📄 socketcomm.cpp
字号:
#include "stdafx.h"
#include <stdio.h>
#include <tchar.h>
#include <process.h>
#include <crtdbg.h>
#include "SocketComm.h"
const DWORD DEFAULT_TIMEOUT = 100L;
SockAddrIn& SockAddrIn::Copy(const SockAddrIn& sin)
{
memcpy(&this->sockAddrIn, &sin.sockAddrIn, Size());
return *this;
}
bool SockAddrIn::IsEqual(const SockAddrIn& sin)
{
// Is it Equal? - ignore 'sin_zero'
return (memcmp(&this->sockAddrIn, &sin.sockAddrIn, Size()-sizeof(sockAddrIn.sin_zero)) == 0);
}
bool SockAddrIn::IsGreater(const SockAddrIn& sin)
{
return (memcmp(&this->sockAddrIn, &sin.sockAddrIn, Size()-sizeof(sockAddrIn.sin_zero)) > 0);
}
bool SockAddrIn::IsLower(const SockAddrIn& sin)
{
return (memcmp(&this->sockAddrIn, &sin.sockAddrIn, Size()-sizeof(sockAddrIn.sin_zero)) < 0);
}
bool SockAddrIn::CreateFrom(LPCTSTR sAddr, LPCTSTR sService)
{
sockAddrIn.sin_addr.s_addr = htonl( CSocketComm::GetIPAddress(sAddr) );
sockAddrIn.sin_port = htons( CSocketComm::GetPortNumber( sService ) );
sockAddrIn.sin_family = AF_INET;
return true;
}
//构造函数
CSocketComm::CSocketComm() :
m_hComm(INVALID_HANDLE_VALUE), m_hMutex(NULL), m_bBroadcast(false), m_hThread(NULL)
{
}
CSocketComm::~CSocketComm()
{
StopComm();
}
bool CSocketComm::IsOpen() const
{
return ( INVALID_HANDLE_VALUE != m_hComm );
}
bool CSocketComm::IsStart() const
{
return ( NULL != m_hThread );
}
bool CSocketComm::IsBroadcast() const
{
return m_bBroadcast;
}
bool CSocketComm::IsSmartAddressing() const
{
return m_bSmartAddressing;
}
SOCKET CSocketComm::GetSocket() const
{
return (SOCKET) m_hComm;
}
//进程互斥
void CSocketComm::LockList()
{
if (NULL != m_hMutex)
WaitForSingleObject(m_hMutex, INFINITE);
}
//解开进程互斥
void CSocketComm::UnlockList()
{
if (NULL != m_hMutex)
ReleaseMutex(m_hMutex);
}
void CSocketComm::AddToList(const SockAddrIn& saddr_in)
{
LockList();
m_AddrList.insert( m_AddrList.end(), saddr_in );
UnlockList();
}
void CSocketComm::RemoveFromList(const SockAddrIn& saddr_in)
{
LockList();
m_AddrList.remove( saddr_in );
UnlockList();
}
//设定
void CSocketComm::SetSmartAddressing(bool bSmartAddressing)
{
if (!IsStart())
m_bSmartAddressing = bSmartAddressing;
}
void CSocketComm::OnDataReceived(const LPBYTE lpBuffer, DWORD dwCount)
{
}
void CSocketComm::OnEvent(UINT uEvent)
{
}
//获得端口号
USHORT CSocketComm::GetPortNumber( LPCTSTR strServiceName )
{
LPSERVENT lpservent;
USHORT nPortNumber = 0;
if ( _istdigit( strServiceName[0] ) ) {
nPortNumber = (USHORT) _ttoi( strServiceName );
}
else {
#ifdef _UNICODE
char pstrService[HOSTNAME_SIZE];
WideCharToMultiByte(CP_ACP, 0, pstrService, -1, strServiceName, sizeof(pstrService), NULL, NULL );
#else
LPCTSTR pstrDevice = strServiceName;
#endif
// 转化网络字节到主机字节
if ( (lpservent = getservbyname( pstrDevice, NULL )) != NULL )
nPortNumber = ntohs( lpservent->s_port );
}
return nPortNumber;
}
ULONG CSocketComm::GetIPAddress( LPCTSTR strHostName )
{
LPHOSTENT lphostent;
ULONG uAddr = INADDR_NONE;
//AfxMessageBox(strHostName);
if ( NULL != strHostName )
{
#ifdef _UNICODE
char strHost[HOSTNAME_SIZE] = { 0 };
WideCharToMultiByte(CP_ACP, 0, strHostName, -1, strHost, sizeof(strHost), NULL, NULL );
#else
LPCTSTR strHost = strHostName;
#endif
// 转化成标准ip地址
//AfxMessageBox(strHost);
uAddr = inet_addr( strHostName );
if ( (INADDR_NONE == uAddr) && (strcmp( strHost, "255.255.255.255" )) )
{
// 获得机器名
if ( lphostent = gethostbyname( strHost ) )
uAddr = *((ULONG *) lphostent->h_addr_list[0]);
}
}
return ntohl( uAddr );
}
//获得本地机器名
bool CSocketComm::GetLocalName(LPTSTR strName, UINT nSize)
{
if (strName!= NULL && nSize > 0)
{
char strHost[HOSTNAME_SIZE] = { 0 };
// 获得机器名
if (SOCKET_ERROR != gethostname(strHost, sizeof(strHost)))
{
struct hostent* hp;
hp = gethostbyname(strHost);
if (hp != NULL) {
strcpy(strHost, hp->h_name);
}
// 检查缓冲区大小
if (strlen(strHost) > nSize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return false;
}
// Unicode转化
#ifdef _UNICODE
return (0 != MultiByteToWideChar(CP_ACP, 0, strHost, -1, strName, nSize, NULL, NULL ));
#else
_tcscpy(strName, strHost);
return true;
#endif
}
}
else
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
bool CSocketComm::GetLocalAddress(LPTSTR strAddress, UINT nSize)
{
// 获得计算机本地地址
if (strAddress != NULL && nSize > 0)
{
char strHost[HOSTNAME_SIZE] = { 0 };
// 获得机器名
if (SOCKET_ERROR != gethostname(strHost, sizeof(strHost)))
{
struct hostent* hp;
hp = gethostbyname(strHost);
if (hp != NULL && hp->h_addr_list[0] != NULL)
{
// 查看地址是否是4字节大小
if ( hp->h_length < 4)
return false;
// 转化地址到点
strHost[0] = 0;
// 创建地址字符创
sprintf(strHost, "%u.%u.%u.%u",
(UINT)(((PBYTE) hp->h_addr_list[0])[0]),
(UINT)(((PBYTE) hp->h_addr_list[0])[1]),
(UINT)(((PBYTE) hp->h_addr_list[0])[2]),
(UINT)(((PBYTE) hp->h_addr_list[0])[3]));
// 检查缓冲区是否足够
if (strlen(strHost) > nSize)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return false;
}
// Unicode转换
#ifdef _UNICODE
return (0 != MultiByteToWideChar(CP_ACP, 0, strHost, -1, strAddress,
nSize, NULL, NULL ));
#else
_tcscpy(strAddress, strHost);
return true;
#endif
}
}
}
else
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
SOCKET CSocketComm::WaitForConnection(SOCKET sock)
{
// 接收一个连接
return accept(sock, 0, 0);
}
//关闭一个连接并关闭一个socket,这将强迫所有的传输和接收失败
bool CSocketComm::ShutdownConnection(SOCKET sock)
{
//
// shutdown(sock, SD_BOTH);
return ( 0 == closesocket( sock ));
}
///////////////////////////////////////////////////////////////////////////////
// GetSockName
///////////////////////////////////////////////////////////////////////////////
// DESCRIPTION:
// retrieves the local name for a socket
// PARAMETERS:
// SockAddrIn& saddr_in: object to store address
///////////////////////////////////////////////////////////////////////////////
//获得socket名称
bool CSocketComm::GetSockName(SockAddrIn& saddr_in)
{
if (IsOpen())
{
int namelen = saddr_in.Size();
return (SOCKET_ERROR != getsockname(GetSocket(), (LPSOCKADDR)saddr_in, &namelen));
}
return false;
}
//获得socket要连接的地址
bool CSocketComm::GetPeerName(SockAddrIn& saddr_in)
{
if (IsOpen())
{
int namelen = saddr_in.Size();
return (SOCKET_ERROR != getpeername(GetSocket(), (LPSOCKADDR)saddr_in, &namelen));
}
return false;
}
//建立连接
bool CSocketComm::ConnectTo(LPCTSTR strDestination, LPCTSTR strServiceName, int nProtocol, int nType)
{
// 如果socket已经打开
if ( IsOpen() )
return false;
SOCKADDR_IN sockAddr = { 0 };
//创建一个socket
SOCKET sock = socket(nProtocol, nType, 0);
if (INVALID_SOCKET != sock)
{
// 让socket绑定一个地址
TCHAR strHost[HOSTNAME_SIZE] = { 0 };
if (false == CSocketComm::GetLocalName( strHost, sizeof(strHost)/sizeof(TCHAR)))
{
closesocket( sock );
return false;
}
//AfxMessageBox(strHost);
sockAddr.sin_addr.s_addr = htonl( CSocketComm::GetIPAddress( strHost ) );
sockAddr.sin_family = nProtocol;
if ( SOCKET_ERROR == bind(sock, (LPSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN)))
{
closesocket( sock );
return false;
}
// 获得目标地址
if ( strDestination[0]) {
sockAddr.sin_addr.s_addr = htonl(CSocketComm::GetIPAddress( strDestination ) );
}
// 获得端口
sockAddr.sin_port = htons( GetPortNumber( strServiceName ) );
if ( 0 != sockAddr.sin_port )
{
// 连接服务器
if (SOCKET_ERROR == connect( sock, (LPSOCKADDR)&sockAddr, sizeof(SOCKADDR_IN)))
{
closesocket( sock );
return false;
}
// 保存socket
m_hComm = (HANDLE) sock;
return true;
}
}
return false;
}
//关闭socket
void CSocketComm::CloseComm()
{
if (IsOpen())
{
//调用ShutdownConnection关闭
ShutdownConnection((SOCKET)m_hComm);
m_hComm = INVALID_HANDLE_VALUE;
m_bBroadcast = false;
}
}
//启动socket通信线程
bool CSocketComm::WatchComm()
{
//首先判断是否启动
if (!IsStart())
{
//判断是否打开通信,即socket是否成功创建
if (IsOpen())
{
HANDLE hThread;
UINT uiThreadId = 0;
//启动线程,使用_beginthreadex
hThread = (HANDLE)_beginthreadex(NULL, // 安全参数
0, // 堆栈
SocketThreadProc, // 线程程序
this, // 线程参数
CREATE_SUSPENDED, //创建模式
&uiThreadId); // 线程ID
//如果线程不为空
if ( NULL != hThread)
{
//继续线程
ResumeThread( hThread );
m_hThread = hThread;
return true;
}
}
}
return false;
}
void CSocketComm::StopComm()
{
// Close Socket
if (IsOpen())
{
CloseComm();
Sleep(50);
}
// Kill Thread
if (IsStart())
{
if (WaitForSingleObject(m_hThread, 5000L) == WAIT_TIMEOUT)
TerminateThread(m_hThread, 1L);
CloseHandle(m_hThread);
m_hThread = NULL;
}
// Clear Address list
if (!m_AddrList.empty())
m_AddrList.clear();
// Destroy Synchronization objects
if (NULL != m_hMutex)
{
CloseHandle( m_hMutex );
m_hMutex = NULL;
}
}
//读入数据
DWORD CSocketComm::ReadComm(LPBYTE lpBuffer, DWORD dwSize, DWORD dwTimeout)
{
_ASSERTE( IsOpen() );
_ASSERTE( lpBuffer != NULL );
if (lpBuffer == NULL || dwSize < 1L)
return 0L;
fd_set fdRead = { 0 };
TIMEVAL stTime;
TIMEVAL *pstTime = NULL;
if ( INFINITE != dwTimeout ) {
stTime.tv_sec = 0;
stTime.tv_usec = dwTimeout*1000;
pstTime = &stTime;
}
SOCKET s = (SOCKET) m_hComm;
// 设定描述符
if ( !FD_ISSET( s, &fdRead ) )
FD_SET( s, &fdRead );
// 选择函数,设定超时时间
DWORD dwBytesRead = 0L;
int res = select( s+1, &fdRead, NULL, NULL, pstTime );
if ( res > 0)
{
if (IsBroadcast() || IsSmartAddressing())
{
SOCKADDR_IN sockAddr = { 0 }; // 获得地址
int nOffset = IsSmartAddressing() ? sizeof(sockAddr) : 0;
int nLen = sizeof(sockAddr);
if ( dwSize < (DWORD) nLen) // 缓冲区太小
{
SetLastError( ERROR_INVALID_USER_BUFFER );
return -1L;
}
//获得数据
res = recvfrom( s, (LPSTR)&lpBuffer[nOffset], dwSize, 0, (LPSOCKADDR)&sockAddr, &nLen);
// clear 'sin_zero', we will ignore them with 'SockAddrIn' anyway!
memset(&sockAddr.sin_zero, 0, sizeof(sockAddr.sin_zero));
if ( res >= 0)
{
LockList(); //锁定地址列表
// 删除调重复地址
SockAddrIn sockin;
sockin.SetAddr( &sockAddr );
m_AddrList.remove( sockin );
m_AddrList.insert(m_AddrList.end(), sockin);
if (IsSmartAddressing())
{
memcpy(lpBuffer, &sockAddr, sizeof(sockAddr));
res += sizeof(sockAddr);
}
UnlockList(); // 解开地址列表
}
}
else
{
res = recv( s, (LPSTR)lpBuffer, dwSize, 0);
}
dwBytesRead = (DWORD)((res > 0)?(res) : (-1));
}
return dwBytesRead;
}
//发送数据
DWORD CSocketComm::WriteComm(const LPBYTE lpBuffer, DWORD dwCount, DWORD dwTimeout)
{
_ASSERTE( IsOpen() );
_ASSERTE( NULL != lpBuffer );
// 如果没有建立连接或者缓冲区为空,则返回
if (!IsOpen() || NULL == lpBuffer)
return 0L;
//fd_set 是一个结构体,
//typedef struct fd_set {
//u_int fd_count; // 数量
//SOCKET fd_array[FD_SETSIZE]; //socket 数组
//} fd_set;
fd_set fdWrite = { 0 };
TIMEVAL stTime;
TIMEVAL *pstTime = NULL;
if ( INFINITE != dwTimeout ) {
stTime.tv_sec = 0;
stTime.tv_usec = dwTimeout*1000;
pstTime = &stTime;
}
SOCKET s = (SOCKET) m_hComm;
// 设定描述符
if ( !FD_ISSET( s, &fdWrite ) )
FD_SET( s, &fdWrite );
// 选择函数设定超时时间
DWORD dwBytesWritten = 0L;
int res = select( s+1, NULL, &fdWrite, NULL, pstTime );
if ( res > 0)
{
// 发送消息广播或者点对点发送
if (IsBroadcast() || IsSmartAddressing())
{
// use offset for Smart addressing
int nOffset = IsSmartAddressing() ? sizeof(SOCKADDR_IN) : 0;
if (IsSmartAddressing())
{
if ( dwCount < sizeof(SOCKADDR_IN)) // error - buffer to small
{
SetLastError( ERROR_INVALID_USER_BUFFER );
return -1L;
}
// 从缓冲区中获得地址
SockAddrIn sockAddr;
sockAddr.SetAddr((SOCKADDR_IN*) lpBuffer);
// 获得地址然后发送
if (sockAddr.sockAddrIn.sin_addr.s_addr != htonl(INADDR_BROADCAST))
{
res = sendto( s, (LPCSTR)&lpBuffer[nOffset], dwCount-nOffset, 0,
(LPSOCKADDR)sockAddr, sockAddr.Size());
dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));
return dwBytesWritten;
}
}
// 向所有用户广播
LockList(); // 锁住地址列表
CSockAddrList::iterator iter = m_AddrList.begin();
for( ; iter != m_AddrList.end(); )
{
//循环发送信息
res = sendto( s, (LPCSTR)&lpBuffer[nOffset], dwCount-nOffset, 0, (LPSOCKADDR)(*iter), iter->Size());
if (res < 0)
{
CSockAddrList::iterator deladdr = iter;
++iter; // 下一个
m_AddrList.erase( deladdr );
}
else
++iter; // 下一个
}
UnlockList(); // 解锁
// UDP总是返回true
res = (int) dwCount - nOffset;
}
else // 发送到单个客户端
res = send( s, (LPCSTR)lpBuffer, dwCount, 0);
dwBytesWritten = (DWORD)((res >= 0)?(res) : (-1));
}
return dwBytesWritten;
}
//该函数由主线程来循环调用
void CSocketComm::Run()
{
BYTE buffer[BUFFER_SIZE];
DWORD dwBytes = 0L;
HANDLE hThread = GetCurrentThread();
DWORD dwTimeout = DEFAULT_TIMEOUT;
//如果socket已经创建
while( IsOpen() )
{
// 采用阻塞式socket,等待事件通知
dwBytes = ReadComm(buffer, sizeof(buffer), dwTimeout);
// 如果有错误发生
if (dwBytes == (DWORD)-1)
{
// 如果要关闭,则不发送事件
if (IsOpen())
OnEvent( EVT_CONDROP ); // 失去连接
break;
}
// 是否有数据收到
if (IsSmartAddressing() && dwBytes == sizeof(SOCKADDR_IN))
OnEvent( EVT_ZEROLENGTH );
else if (dwBytes > 0L)
{
OnDataReceived( buffer, dwBytes);
}
Sleep(0);
}
}
//socket线程
UINT WINAPI CSocketComm::SocketThreadProc(LPVOID pParam)
{
//reinterpret_cast用于各种指针的转化
CSocketComm* pThis = reinterpret_cast<CSocketComm*>( pParam );
_ASSERTE( pThis != NULL );
pThis->Run();
return 1L;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -