WSAClientSocket继承自ClientSocket,完成对基本WinSock函数的封装。
ClientSocket只是提供一个接口,具体实现由其继承类WSAClientSocket(WINDOWS)和UClientSocket (UNIX)实现
这里先介绍一下Host类:
unsigned int ip; //主机IP
unsigned short port; //主机端口号
unsigned int value;
下面介绍一下WSAClientSocket的具体实现
//初始化,每个Winsock应用都必须加载合适的WinSock DLL版本.加载库是通过调用WSAStartup函数实现的
void WSAClientSocket::init()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 0 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 )
throw SockException("Unable to init sockets");
}
//建立套接字,通过调用socket函数来实现
void WSAClientSocket::open(Host &rh)
{
sockNum = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockNum == INVALID_SOCKET)
throw SockException("Can`t open socket");
setBlocking(false);
#ifdef DISABLE_NAGLE
setNagle(false);
#endif
host = rh;
memset(&remoteAddr,0,sizeof(remoteAddr));
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons(host.port);
remoteAddr.sin_addr.S_un.S_addr = htonl(host.ip);
}
//服务器绑定。一旦为某种协议创建了套接字,就必须将套接字绑定到一个已知地址上。使用bind函数
void WSAClientSocket::bind(Host &h)
{
struct sockaddr_in localAddr;
if ((sockNum = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
throw SockException("Can`t open socket");
setBlocking(false);
setReuse(true);
memset(&localAddr,0,sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(h.port);
localAddr.sin_addr.s_addr = INADDR_ANY;
if( ::bind (sockNum, (sockaddr *)&localAddr, sizeof(localAddr)) == -1)
throw SockException("Can`t bind socket");
//接下来要做的,是将套接字置入监听模式。bind函数的作用只是将套接字和指定的地址关联在一起。指示套接字等待连接传入的API是listen
if (::listen(sockNum,SOMAXCONN))
throw SockException("Can`t listen",WSAGetLastError());
host = h;
}
//现在我们已做好了接受客户机连接的准备,通过ACCEPT函数来完成
ClientSocket *WSAClientSocket::accept()
{
int fromSize = sizeof(sockaddr_in);
sockaddr_in from;
int conSock = ::accept(sockNum,(sockaddr *)&from,&fromSize);
if (conSock == INVALID_SOCKET)
return NULL;
WSAClientSocket *cs = new WSAClientSocket();
cs->sockNum = conSock;
cs->host.port = from.sin_port;
cs->host.ip = from.sin_addr.S_un.S_un_b.s_b1<<24 |
from.sin_addr.S_un.S_un_b.s_b2<<16 |
from.sin_addr.S_un.S_un_b.s_b3<<8 |
from.sin_addr.S_un.S_un_b.s_b4;
cs->setBlocking(false);
#ifdef DISABLE_NAGLE
cs->setNagle(false);
#endif
return cs;
}
//关闭套接字
void WSAClientSocket::close()
{
if (sockNum)
{
shutdown(sockNum,SD_SEND);
setReadTimeout(2000);
try
{
//char c;
//while (readUpto(&c,1)!=0);
//readUpto(&c,1);
}catch(StreamException &) {}
if (closesocket(sockNum))
LOG_ERROR("closesocket() error");
sockNum=0;
}
}
//客户端连接
void WSAClientSocket::connect()
{
if (::connect(sockNum,(struct sockaddr *)&remoteAddr,sizeof(remoteAddr)) == SOCKET_ERROR)
checkTimeout(false,true);
}
//发送数据
void WSAClientSocket::write(const void *p, int l)
{
while (l)
{
int r = send(sockNum, (char *)p, l, 0);
if (r == SOCKET_ERROR)
{
checkTimeout(false,true);
}
else if (r == 0)
{
throw SockException("Closed on write");
}
else
if (r > 0)
{
stats.add(Stats::BYTESOUT,r);
if (host.localIP())
stats.add(Stats::LOCALBYTESOUT,r);
updateTotals(0,r);
l -= r;
p = (char *)p+r;
}
}
}
//接收数据
int WSAClientSocket::read(void *p, int l)
{
int bytesRead=0;
while (l)
{
int r = recv(sockNum, (char *)p, l, 0);
if (r == SOCKET_ERROR)
{
// non-blocking sockets always fall through to here
checkTimeout(true,false);
}else if (r == 0)
{
throw EOFException("Closed on read");
}else
{
stats.add(Stats::BYTESIN,r);
if (host.localIP())
stats.add(Stats::LOCALBYTESIN,r);
updateTotals(r,0);
bytesRead += r;
l -= r;
p = (char *)p+r;
}
}
return bytesRead;
}