📄 socket.cpp
字号:
/***************************************************************************
socket.cpp - description
-------------------
begin : Fri Jul 20 2001
copyright : (C) 2001 by Mark
email : alben@yeah.net
modifier : yt yfrom_to@sina.com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <cstring>
#include <cstdio>
#include <iostream>
#include "mylibconf.h"
#include "socket.h"
using namespace std;
//#include <AFX.H>
namespace mylib
{
//存储本地ip,端口号
void CSocket::StoreLocalIP_PORT()
{
CInetAddress localInet;
#if defined(WIN32)
int nLen=sizeof(sockaddr);
#else
socklen_t nLen=sizeof(CInetAddress);
#endif
getsockname(m_iSocket,(sockaddr*)&localInet.m_stInetAddr,&nLen);
m_InetAddr=localInet;
}
#if defined(WIN32)
Cinit_WSA::Cinit_WSA()
{
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
abort();
}
}
Cinit_WSA::~Cinit_WSA()
{ WSACleanup(); }
#endif
CInetAddress::CInetAddress()
{
memset(&m_stInetAddr, 0, sizeof(m_stInetAddr));
}
CInetAddress::CInetAddress(const struct sockaddr_in& stInetAddr)
{
m_stInetAddr = stInetAddr;
}
//CInetAddress::CInetAddress(const char* sInetAddr)
//{
// memset(&m_stInetAddr, 0, sizeof(m_stInetAddr));
// *this=sInetAddr;
//}
CInetAddress::CInetAddress(const char* ipAddr,int port)
{
memset(&m_stInetAddr, 0, sizeof(m_stInetAddr));
m_stInetAddr.sin_family = AF_INET;
m_stInetAddr.sin_port = htons(port);
if (strcmp(ipAddr, "*") == 0)
{
m_stInetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
return;
}
if( (m_stInetAddr.sin_addr.s_addr=inet_addr(ipAddr)) == INADDR_NONE)
{// Internet host information structure
struct hostent *lpHostEnt;
#if defined(WIN32)
if (!(lpHostEnt = gethostbyname(ipAddr)))
{
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
}
#else
if (!(lpHostEnt = gethostbyname(ipAddr)))
{
throw CSocketException(strerror(errno), __FILE__, __LINE__);
}
#endif
m_stInetAddr= *((struct sockaddr_in *)lpHostEnt->h_addr_list[0]);
}
}
bool CInetAddress::IsInetAddress() const
{
struct sockaddr_in stInetAddr;
memset(&stInetAddr, 0, sizeof(stInetAddr));
if(memcmp(&m_stInetAddr, &stInetAddr, sizeof(m_stInetAddr)))
return true;
return false;
}
std::string CInetAddress::GetIPaddstr(const char splitch) const
{
if(m_stInetAddr.sin_addr.s_addr==INADDR_ANY)
return string("");
char strCmd[128];
#if defined(MYLIB_BIG_ENDIAN)
sprintf(strCmd, "%d%c%d%c%d%c%d",
(m_stInetAddr.sin_addr.s_addr>>24) & 0x000000ff,
splitch,
(m_stInetAddr.sin_addr.s_addr>>16) & 0x000000ff,
splitch,
(m_stInetAddr.sin_addr.s_addr>>8) & 0x000000ff,
splitch,
(m_stInetAddr.sin_addr.s_addr) & 0x000000ff
);
#elif defined(MYLIB_LITTLE_ENDIAN)
sprintf(strCmd, "%d%c%d%c%d%c%d",
(m_stInetAddr.sin_addr.s_addr) & 0x000000ff,
splitch,
(m_stInetAddr.sin_addr.s_addr>>8) & 0x000000ff,
splitch,
(m_stInetAddr.sin_addr.s_addr>>16) & 0x000000ff,
splitch,
(m_stInetAddr.sin_addr.s_addr>>24) & 0x000000ff
);
#endif
return string(strCmd);
}
CInetAddress& CInetAddress::operator = (const CInetAddress& sInetAddr)
{
m_stInetAddr=sInetAddr.m_stInetAddr;
return *this;
}
CInetAddress& CInetAddress::operator = (const struct sockaddr_in& stInetAddr)
{
m_stInetAddr = stInetAddr;
return *this;
}
/////////////////////////////////////////////////////////////////////////
// 函数名:operator =
// 作 用:初始化,赋值内部数据。
// 参 数:"IP地址,端口号" 或者 "主机名:端口号"
// 返回值:CInetAddress&
// 修 改:
/////////////////////////////////////////////////////////////////////////
//CInetAddress& CInetAddress::operator = (const char* sInetAddr)
//{
//
// char *strport=strchr(sInetAddr,':');
// if(strport==0)
// return *this;
// ++strport;//skip the ':'
//
// char stripaddr[20];
// char *pp=stripaddr;
// for(const char *p=sInetAddr;p!=strport;p++)
// *pp++=*p;
// *pp='\0';
//
// if (strcmp(stripaddr, "*") == 0)
// {
// m_stInetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
// return *this;
// }
//
// m_stInetAddr.sin_family = AF_INET;
// m_stInetAddr.sin_port = htons(atol(strport));
//
//
// //////////////////////////////////////////////////////////////////////////
// //没有使用gethostbyname_r
// //////////////////////////////////////////////////////////////////////////
//
// if( (m_stInetAddr.sin_addr.s_addr=inet_addr(stripaddr)) == INADDR_NONE)
// {// Internet host information structure
// struct hostent *lpHostEnt;
// if (!(lpHostEnt = gethostbyname(stripaddr)))
// {
// #if defined(WIN32)
// throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
// #else
// throw CSocketException(strerror(errno), __FILE__, __LINE__);
// #endif
// }
// m_stInetAddr= *((struct sockaddr_in *)lpHostEnt->h_addr_list[0]);
// }
// return *this;
//}
CSocket::CSocket(int iDomain, int iType, int iProtocol)
{
Init();
m_iDomain = iDomain;
Socket(iDomain, iType, iProtocol);
m_eState = S_AVAILABLE;
}
void CSocket::Socket(int iDomain, int iType, int iProtocol) throw(CSocketException)
{
if ((m_iSocket = socket(iDomain, iType, iProtocol)) < 0)
#if defined(WIN32)
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
#else
throw CSocketException(strerror(errno), __FILE__, __LINE__);
#endif
}
void CSocket::SockREUSEADDR()
{
int optval =1;
if(setsockopt(m_iSocket, SOL_SOCKET, SO_REUSEADDR,(char*) &optval, sizeof(optval))!=0)
#if defined(WIN32)
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
#else
throw CSocketException(strerror(errno), __FILE__, __LINE__);
#endif
}
void CSocket::Init()
{
m_iSocket = INVALID_SOCKET;
m_eState = S_INITIAL;
m_bBlock = true;
}
//use Shutdown(1) close write channel,All OS are same;
//use Shutdown(0)
//UNIX: reflush the read queue,when has data receive,only ACK
//WINDOWS: reset the link
int CSocket::Shutdown(int how) throw()
{
return shutdown(m_iSocket,how);
}
void CSocket::End() throw()
{
if (m_iSocket <=0 || (m_iSocket==INVALID_SOCKET) )
{
m_iSocket = INVALID_SOCKET;
m_eState = S_INITIAL;
return;
}
#if defined(WIN32)
::closesocket(m_iSocket);
#else
::close(m_iSocket);
#endif
cerr<<"close "<<m_iSocket<<endl;
m_iSocket = INVALID_SOCKET;
m_eState = S_INITIAL;
}
void CSocket::SetBlock(bool bBlock) throw (CSocketException)
{
#if defined(WIN32)
int iFlag;
u_long in_out_args;
if(bBlock==false)
{
in_out_args=1;
iFlag=ioctlsocket(m_iSocket,FIONBIO ,&in_out_args);
if(iFlag<0)
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
}
else
{
in_out_args=0;
iFlag=ioctlsocket(m_iSocket,FIONBIO ,&in_out_args);
if(iFlag == SOCKET_ERROR)
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
}
#else
int iFlag = fcntl(m_iSocket, F_GETFL);
if (iFlag < 0)
throw CSocketException(strerror(errno), __FILE__, __LINE__);
if (bBlock)
iFlag &= ~O_NONBLOCK;
else
iFlag |= O_NONBLOCK;
if (fcntl(m_iSocket, F_SETFL, iFlag) < 0)
throw CSocketException(strerror(errno), __FILE__, __LINE__);
#endif
m_bBlock = bBlock;
}
void CSocket::ServerBind(const tcport_t tPort)
{
struct sockaddr_in stSockAddr;
memset(&stSockAddr, 0, sizeof(stSockAddr));
stSockAddr.sin_family = AF_INET;
stSockAddr.sin_port = htons(tPort);
stSockAddr.sin_addr.s_addr = INADDR_ANY;
m_InetAddr=stSockAddr;
m_eState = S_BOUND;
cerr<<"serv bound!\n";
if (bind(m_iSocket, (struct sockaddr*)&stSockAddr, sizeof(stSockAddr)) < 0)
#if defined(WIN32)
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
#else
throw CSocketException(strerror(errno), __FILE__, __LINE__);
#endif
//由系统分配端口,此时只有端口号可得
if(tPort==0)
StoreLocalIP_PORT();
}
void CSocket::SetMember(int socki,bool ifblock,CState st,int domaini)
{
m_iSocket = socki;
SetBlock(ifblock);
m_eState = st;
m_iDomain = domaini;
}
//服务器使用
CTcpSocket::CTcpSocket(const tcport_t tPort)
: CSocket(AF_INET, SOCK_STREAM)
{
ServerBind(tPort);
}
//客户端使用
CTcpSocket::CTcpSocket()
: CSocket(AF_INET, SOCK_STREAM)
{
}
bool CTcpSocket::Accept(CSocket &connectsock)
{
struct sockaddr_in stInetSockAddr;
//struct sockaddr_un stUnixSockAddr;
#if defined(WIN32)
int tSockLen;
#else
socklen_t tSockLen;
#endif
sockaddr* pstSockAddr;
pstSockAddr = (sockaddr*)&stInetSockAddr;
tSockLen = sizeof(stInetSockAddr);
while (true)
{
#if defined(WIN32)
SOCKET i(INVALID_SOCKET)
#else
int i=-1;
#endif
i= accept(m_iSocket, pstSockAddr, /*(int*)*/&tSockLen);
cerr<<"acc "<<i<<'\n';
#if defined(WIN32)
if (i == INVALID_SOCKET)
{
if (m_bBlock)
{
if (!OnAcceptIntr())
continue;
else
return false;
}
if ( (!m_bBlock) && (WSAGetLastError()==WSAEWOULDBLOCK) )
return false;
throw CSocketException(STRERROR_WIN(WIN32_SYS_WINSOCK), __FILE__, __LINE__);
#else
if (i < 0)
{
if (m_bBlock && errno == EINTR)
{
if (!OnAcceptIntr())
continue;
else
return false;
}
if ( (!m_bBlock) && (errno == EWOULDBLOCK
#ifdef ECONNABORTED
|| errno == ECONNABORTED
#endif
#ifdef EPROTO
|| errno == EPROTO
#endif
) )
return false;
throw CSocketException(strerror(errno), __FILE__, __LINE__);
#endif
}//end of "if (i == "
//maybe reject special IP
if (!OnAccept(stInetSockAddr, ntohs(stInetSockAddr.sin_port)))
{
#if defined(WIN32)
::closesocket(m_iSocket);
#else
::close(m_iSocket);
#endif
return false;
}
connectsock.SetMember(i,m_bBlock,S_CONNECTED,m_iDomain);
return true;
}//end while
return false;
}
/////////////////////////////////////////////////////////////////////////
// 函数名:AcceptwithTmOut
// 作 用:接受新连接。
// 参 数:CSocket &connectsock ,秒 nSec,毫秒 int nMs UNIX只能精确到10ms
// 返回值:超时:TIMEROUT_,成功返回0,错误返回负值,其他throw exception
// 修 改:
/////////////////////////////////////////////////////////////////////////
int CTcpSocket::AcceptwithTmOut(CSocket &connectsock,int nSec,int nMs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -