能力值:
( LV8,RANK:130 )
|
-
-
9 楼
说实话的,楼主封闭得不是很好,不知道你平时写网络程序不?一个成熟的网络程序员,封装出来的东西,应该不是这么简单。。
不是打击你,你封装和真的不好,还不如直接使用socket来写,
不过,你的精神可佳,
随便秀一下我封装的吧,给你参考一下:
我封装的这个,是阻塞式操作,还有异步操作和IOCP等封装就不发上来了,
/***********************************************************************
版权所有:choday
文件名称:XSocket.h
描 述:基本socket封
作 者:choday
创建日期:2011-10-17 17:08:58
修 改 人:choday
修改日期:
修改原因:
***********************************************************************/
#pragma once
#ifndef SOCKETX_H
#define SOCKETX_H
#ifndef _WINSOCK2API_
#ifdef _WINDOWS_
# ifndef WIN32_LEAN_AND_MEAN
#error >>>>>>>>> you must define WIN32_LEAN_AND_MEAN before include <windows.h> <<<<<<<<
# endif
#endif
#include <winsock2.h>
#endif
namespace XLIB
{
/*
#ifndef _WINSOCK2API_
typedef struct sockaddr SOCKADDR;
typedef unsigned int SOCKET;
#define SOCK_STREAM 1
#define IPPROTO_TCP 6
#ifndef SOMAXCONN
#define SOMAXCONN 0x7fffffff
#endif
#endif
*/
class CXSocket
{
public:
CXSocket();
~CXSocket();
static VOID Initialize();
static VOID UnInitialize();
static DWORD GetHostIPv4( const char* hostname );
static VOID ParserString( LPCTSTR lpAddress,SOCKADDR* name,int namelen);
VOID Attach( SOCKET hSocket );
VOID Dettach();
SOCKET GetHandle(){ return m_hSocket;}
BOOL Create( int type = SOCK_STREAM ,int protocol = IPPROTO_TCP );//SOCK_DGRAM,IPPROTO_UDP
VOID Close();
//socket 参数设置
BOOL SetRecvTimeOut( DWORD dwTimeOut );
BOOL SetSendTimeOut( DWORD dwTimeOut );
BOOL SelectForRead( DWORD dwTimeOut = 0);//是否可以读数据了,单位毫秒
BOOL SelectForWrite( DWORD dwTimeOut = 0);//是否可以写数据了,单位毫秒
VOID DisableUDPReset(); //说明见CPP
VOID EnableUDPBroadcast( BOOL Enable = TRUE );
BOOL EnableBlockingMode( BOOL Enable = TRUE );//设置为阻塞模式
BOOL EnableReuseAddr( BOOL Enable = TRUE );//设置为端口重用模式
BOOL EnableKeepAlive( BOOL Enable,DWORD AliveTime = 60*2,DWORD IntervalTime=60*4 );//TCP存活保持,,单位毫秒,AliveTime毫秒后开始自动发送存活包,如果没有收到返回包,将在间隔IntervalTime毫秒后重发
//获取socket绑定地址
BOOL GetSockName( SOCKADDR* pname,int *namelen = 0);
BOOL GetPeerName( SOCKADDR* pname,int *namelen = 0);
//绑定
BOOL Bind(const SOCKADDR *pAddr,int naddrlen = 0);
BOOL Bind( DWORD dwIP,USHORT uPort );//uPort网络顺序,如果端口是89,应该写htons(89)转换成网络顺序
BOOL Bind( int nPort = 0 );//一般顺序,端口89,就写89
//监听
BOOL Listen( int backlog = SOMAXCONN );
//接受连接
SOCKET Accept(SOCKADDR* pAddr,int naddrlen = 0 );
SOCKET Accept(DWORD *pRemoteIP = 0,USHORT *pPort = 0);
//发起连接
BOOL Connect( const SOCKADDR* paddr,int naddrlen = 0 );
BOOL Connect( DWORD dwRemoteIP,USHORT uPort );//uPort网络顺序
BOOL Connect( const char* lpszRemotehost,int nPort );//
int GetConnectTime();
//数据读写
int Send( LPCVOID lpbuffer,int nlen );//失败返回0
int Recv( LPVOID lpbuffer,int nlen,int flags=0 );//失败返回0
int SendBlock( LPCVOID lpbuffer,int nlen); //发送一个数据块,直接到nlen数据发送完才返回//失败返回0
int RecvBlock( LPVOID lpbuffer,int nlen); //接收一个数据块,直到将缓冲区占满才返回//失败返回0
int SendTo( LPCVOID lpbuffer,int nlen,const SOCKADDR* pSendToAddr,int naddrlen = 0,int flags=0 );//失败返回0
int RecvFrom( LPVOID lpbuffer,int nlen,SOCKADDR* pRecvFromAddr,int flags=0 );//失败返回0
protected:
SOCKET m_hSocket;
struct tcp_keepalive {
ULONG onoff;
ULONG keepalivetime;
ULONG keepaliveinterval;
};
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
};
}
#endif
/***********************************************************************
版权所有:choday
文件名称:XSocket.cpp
描 述:
作 者:choday
创建日期:2011-10-17 17:07:10
修 改 人:choday
修改日期:
修改原因:
***********************************************************************/
#include "stdafx.h"
#include <winsock2.h>
#include <Mstcpip.h>
#include "SocketX.h"
namespace XLIB
{
#pragma comment( lib,"ws2_32.lib")
#ifndef SIO_UDP_CONNRESET
#define IOC_VENDOR 0x18000000
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
#endif
CXSocket::CXSocket()
{
Initialize();
m_hSocket = INVALID_SOCKET;
}
CXSocket::~CXSocket()
{
UnInitialize();
m_hSocket = INVALID_SOCKET;
}
VOID CXSocket::Initialize()
{
WSADATA wsaData;
WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
}
VOID CXSocket::UnInitialize()
{
WSACleanup();
}
VOID CXSocket::ParserString( LPCTSTR lpAddress,SOCKADDR* name,int namelen)
{
char host[64] = {0};
ZeroMemory( name,namelen);
name->sa_family = AF_INET;
for( int i = 0;i<lstrlen(lpAddress)&&i<64;i++)
{
if( ':' == lpAddress[i] )
{
LPSOCKADDR_IN(name)->sin_port = htons( _ttoi(&lpAddress[i+1]) );
LPSOCKADDR_IN(name)->sin_addr.S_un.S_addr = GetHostIPv4(host);
break;
}
host[i] = (char)lpAddress[i];
}
}
DWORD CXSocket::GetHostIPv4( const char* host_name )
{
struct hostent *remoteHost;
struct in_addr addr;
if(isalpha(host_name[0]))
{ /* host address is a name */
remoteHost = gethostbyname(host_name);
}
else
{
addr.s_addr = inet_addr(host_name);
return addr.s_addr;
}
if (remoteHost == NULL)
{
return 0;
} else
{
/*
printf("Function returned:\n");
printf("\tOfficial name: %s\n", remoteHost->h_name);
printf("\tAlternate names: %s\n", remoteHost->h_aliases);
printf("\tAddress type: ");
switch (remoteHost->h_addrtype) {
case AF_INET:
printf("AF_INET\n");
break;
case AF_INET6:
printf("AF_INET\n");
break;
case AF_NETBIOS:
printf("AF_NETBIOS\n");
break;
default:
printf(" %d\n", remoteHost->h_addrtype);
break;
}
printf("\tAddress length: %d\n", remoteHost->h_length);
*/
return *(DWORD *)remoteHost->h_addr_list[0];
}
return addr.s_addr;
}
VOID CXSocket::Attach( SOCKET hSocket )
{
m_hSocket = hSocket;
}
VOID CXSocket::Dettach()
{
m_hSocket = INVALID_SOCKET;
}
BOOL CXSocket::Create( int type ,int protocol )
{
m_hSocket = socket( AF_INET,type,protocol );
if( INVALID_SOCKET == m_hSocket )return FALSE;
DisableUDPReset();
return TRUE;
}
VOID CXSocket::Close()
{
if( INVALID_SOCKET!=m_hSocket )closesocket(m_hSocket);
m_hSocket = INVALID_SOCKET;
}
BOOL CXSocket::Bind(const SOCKADDR* pAddr,int naddrlen )
{
if( 0 == naddrlen ) naddrlen = sizeof(SOCKADDR);
if( SOCKET_ERROR == bind( m_hSocket,(const SOCKADDR*)pAddr,naddrlen ) )return FALSE;
return TRUE;
}
BOOL CXSocket::Bind( DWORD dwIP,USHORT uPort )
{
sockaddr_in addr;
ZeroMemory( &addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = dwIP;
addr.sin_port = uPort;
return Bind((const SOCKADDR*)&addr);
}
BOOL CXSocket::Bind( int nPort )
{
return Bind(0,htons(nPort));
}//一般顺序,端口89,就写89
BOOL CXSocket::SetRecvTimeOut( DWORD dwTimeOut )
{
int timeout = dwTimeOut ;
int optlen = sizeof(optlen);
int nRet;
nRet = setsockopt( m_hSocket, SOL_SOCKET, SO_RCVTIMEO ,(const char *)&timeout, optlen);
if( -1 == nRet )return FALSE;
return TRUE;
}
BOOL CXSocket::SetSendTimeOut( DWORD dwTimeOut )
{
int timeout = dwTimeOut ;
int optlen = sizeof(optlen);
int nRet;
nRet = setsockopt( m_hSocket, SOL_SOCKET, SO_SNDTIMEO ,(const char *)&timeout, optlen);
if( -1 == nRet )return FALSE;
return TRUE;
}
BOOL CXSocket::SelectForRead( DWORD dwTimeOut )
{
TIMEVAL time;
fd_set fread;
int nRet;
time.tv_sec = dwTimeOut/1000;
time.tv_usec = 0;
FD_ZERO(&fread);
FD_SET( m_hSocket,&fread);
nRet = select( 0,&fread,0,0,&time );
if( nRet <= 0 )return FALSE;
return TRUE;
}
BOOL CXSocket::SelectForWrite( DWORD dwTimeOut )
{
TIMEVAL time;
fd_set fwrite;
int nRet;
time.tv_sec = dwTimeOut/1000;
time.tv_usec = 0;
FD_ZERO(&fwrite);
FD_SET( m_hSocket,&fwrite);
nRet = select( 0,0,&fwrite,0,&time );
if( nRet <= 0 )return FALSE;
return TRUE;
}
BOOL CXSocket::Listen( int backlog )
{
if( SOCKET_ERROR == listen( m_hSocket,backlog ) )return FALSE;
return TRUE;
}
SOCKET CXSocket::Accept(DWORD *pRemoteIP,USHORT *pPort)
{
DWORD RemoteIP = 0;
USHORT Port = 0;
SOCKET s;
sockaddr_in addr;
int nLen;
if( pRemoteIP ) RemoteIP = *pRemoteIP;
if( pPort ) Port = *pPort;
ZeroMemory( &addr,sizeof(addr));
addr.sin_family = AF_INET;
nLen = sizeof(SOCKADDR);
s = accept( m_hSocket,(SOCKADDR*)&addr,&nLen );
if( pRemoteIP ) *pRemoteIP = addr.sin_addr.S_un.S_addr;
if( pPort ) *pPort = addr.sin_port;
return s;
}
SOCKET CXSocket::Accept( SOCKADDR* pAddr,int naddrlen )
{
SOCKET s;
if( 0 == naddrlen ) naddrlen = sizeof(SOCKADDR);
s = accept( m_hSocket,(SOCKADDR*)pAddr,&naddrlen );
return s;
}
BOOL CXSocket::Connect( const SOCKADDR* paddr,int naddrlen )
{
if( 0 == naddrlen ) naddrlen = sizeof(SOCKADDR);
if( SOCKET_ERROR == connect( m_hSocket,paddr,naddrlen ) )return FALSE;
return TRUE;
}
BOOL CXSocket::Connect( DWORD dwRemoteIP,USHORT uPort )
{
sockaddr_in addr;
ZeroMemory( &addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = dwRemoteIP;
addr.sin_port = uPort;
return Connect( (const SOCKADDR*)&addr );
}
BOOL CXSocket::Connect( const char* lpszRemotehost,int nPort )
{
return Connect( GetHostIPv4(lpszRemotehost),htons(nPort) );
}
int CXSocket::GetConnectTime()
{
int nValue = 0;
int nLength = sizeof(nValue);
//#define SO_CONNECT_TIME 0x700C
int nRet = getsockopt( m_hSocket, SOL_SOCKET, 0x700C,(char *)&nValue,(PINT)&nLength );
if( -1 == nRet || -1 == nValue )return FALSE;
return nValue;
}
int CXSocket::Send( LPCVOID lpbuffer,int nlen )
{
int nRet;
nRet = send( m_hSocket,(const char*)lpbuffer,nlen,0 );
if( SOCKET_ERROR == nRet )return 0;
return nRet;
}
int CXSocket::Recv( LPVOID lpbuffer,int nlen,int flags )
{
int nRet;
nRet = recv( m_hSocket,(char*)lpbuffer,nlen,flags );
if( SOCKET_ERROR == nRet )return 0;
return nRet;
}
int CXSocket::SendBlock( LPCVOID lpbuffer,int nlen)
{
int nRet;
int TotalLen = nlen;
int nSentBytes = 0;
LPBYTE lpByter = (LPBYTE)lpbuffer;
while( TotalLen > 0 )
{
nRet = Send( &lpByter[nSentBytes],TotalLen );
if( 0 == nRet )break;
nSentBytes += nRet;
TotalLen -= nRet;
}
return nSentBytes;
}
int CXSocket::RecvBlock(LPVOID lpbuffer,int nlen)
{
int nRet;
int TotalLen = nlen;
int nRecvBytes = 0;
LPBYTE lpBytes = (LPBYTE)lpbuffer;
while( TotalLen > 0 )
{
nRet = Recv( &lpBytes[nRecvBytes],TotalLen );
if( 0 == nRet )break;
nRecvBytes += nRet;
TotalLen -= nRet;
}
return nRecvBytes;
}
int CXSocket::SendTo( LPCVOID lpbuffer,int nlen,const SOCKADDR* pSendToAddr,int naddrlen,int flags )
{
int nRet;
if( 0 == naddrlen ) naddrlen = sizeof(SOCKADDR);
nRet = sendto( m_hSocket,(const char*)lpbuffer,nlen,flags,(const SOCKADDR*)pSendToAddr,naddrlen );
if( SOCKET_ERROR == nRet )return 0;
return nRet;
}
int CXSocket::RecvFrom( LPVOID lpbuffer,int nlen,SOCKADDR* pRecvFromAddr,int flags )
{
int nRet;
int Namelen = sizeof(SOCKADDR);
SOCKADDR addr;
ZeroMemory( &addr,sizeof(addr) );
addr.sa_family = AF_INET;
if( 0 == pRecvFromAddr )pRecvFromAddr=&addr;
nRet = recvfrom( m_hSocket,(char*)lpbuffer,nlen,flags,(SOCKADDR*)pRecvFromAddr,&Namelen );
if( SOCKET_ERROR == nRet )return 0;
return nRet;
}
/*
今天team里同事在Windows XP下调一个UDP server时发现recvfrom会返回WSAECONNRESET。以前没出现过这个问题。后来在网上查了一下把问题解决了,做个笔记。
原因:server用同一个udp socket来发送和接收,发送和接收在不同的线程里进行。启动时,接收线程会在recvfrom阻塞,发送线程向远端host的ip和端口发送数据,若此ip存在且没有程序打开此端口,该host可能会返回icmp的port reachable消息(自己猜的),把socket置为错误状态,从而导致recvfrom返回错误WSAECONNRESET。
*/
VOID CXSocket::DisableUDPReset()
{
BOOL bNewBehavior = FALSE;
DWORD dwBytesReturned;
WSAIoctl( m_hSocket,SIO_UDP_CONNRESET,&bNewBehavior,sizeof(bNewBehavior),NULL,0,&dwBytesReturned,NULL,NULL);
}
VOID CXSocket::EnableUDPBroadcast( BOOL Enable )
{
int iOptionValue = (int)Enable;
setsockopt( m_hSocket,SOL_SOCKET,SO_BROADCAST, (const char*)&iOptionValue, sizeof(int));
}
BOOL CXSocket::EnableBlockingMode( BOOL Enable )
{
//-------------------------
// Set the socket I/O mode: In this case FIONBIO
// enables or disables the blocking mode for the
// socket based on the numerical value of iMode.
// If iMode = 0, blocking is enabled;
// If iMode != 0, non-blocking mode is enabled.
u_long iMode = (u_long)(TRUE==Enable?0:1);
return -1 != ioctlsocket( m_hSocket, FIONBIO, &iMode);
}
BOOL CXSocket::EnableReuseAddr( BOOL Enable )
{
int iOptionValue = (int)Enable;
return -1 != setsockopt( m_hSocket,SOL_SOCKET,SO_REUSEADDR, (const char*)&iOptionValue, sizeof(int));
}
BOOL CXSocket::EnableKeepAlive( BOOL Enable,DWORD AliveTime,DWORD IntervalTime )
{
tcp_keepalive sKA_Settings = {0}, sReturned = {0} ;
DWORD dwBytes = 0;
sKA_Settings.onoff = Enable ;
sKA_Settings.keepalivetime = AliveTime ; // Keep Alive in 5.5 sec.
sKA_Settings.keepaliveinterval = IntervalTime ; // Resend if No-Reply
if (WSAIoctl( m_hSocket, SIO_KEEPALIVE_VALS, &sKA_Settings,
sizeof(sKA_Settings), &sReturned, sizeof(sReturned), &dwBytes,
NULL, NULL) == SOCKET_ERROR)
{
return FALSE;
}
return TRUE;
}
BOOL CXSocket::GetSockName( SOCKADDR* pname,int *namelen)
{
int len = sizeof(SOCKADDR);
if( 0 == namelen )namelen = &len;
return 0 == ::getsockname( m_hSocket,pname,namelen );
}
BOOL CXSocket::GetPeerName( SOCKADDR* pname,int *namelen)
{
int len = sizeof(SOCKADDR);
if( 0 == namelen )namelen = &len;
return 0 == ::getpeername( m_hSocket,pname,namelen );
}
}
|
能力值:
( LV8,RANK:130 )
|
-
-
10 楼
顺便给你挑个错误
在下面的代码中:
错误1==>对主机名转换不正确,不全面
你只判断了lpszHost为www网址的情况 ,没有判断其它的情况 ,比如bbs.pediy.com
如果传入的字符串中没有www的话,你会直接调用inet_addr,这个函数只能用来转换ip地址的字符串,不能将主机名转换成ip地址,
错误2==>你的lpszHost参数类型是LPCTSTR ,如果编译环境为unicode的时候,你的代码将编译通不过,因为inet_addr只接受ansi字符串,所以你的这个是错误的
//创建客户端
int CSocket::Client(UINT nPort, LPCTSTR lpszHost)
{
if(TRUE != Startup())
{
CloseClient();
throw ECSocket(ECSocket::WSA_VER);
}
m_hClientSocket = socket(AF_INET, m_nSockType,m_nProtoType);
if ( INVALID_SOCKET == m_hClientSocket )
{
CloseClient();
throw ECSocket(ECSocket::WSA_INVALID_SOCKET);
}
if(NULL != strstr(lpszHost,"www.") || NULL != strstr(lpszHost,"WWW."))
{
struct hostent * host = gethostbyname(lpszHost);
if(NULL != host)
{
m_hClientSock.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
}
else
{
CloseClient();
throw ECSocket(ECSocket::WSA_GETHOSTBY_NAME_ADDR);
}
}
else
{
m_hClientSock.sin_addr.S_un.S_addr = inet_addr(lpszHost);
}
m_hClientSock.sin_family = AF_INET;
m_hClientSock.sin_port = htons(nPort);
if( SOCKET_ERROR == connect(m_hClientSocket,(SOCKADDR*)&m_hClientSock,sizeof(m_hClientSock)))
{
CloseClient();
throw ECSocket(ECSocket::WSA_CONNECT);
}
return 0;
}
|