⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 csocket.cpp

📁 sun Linux 下的网络编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	{
		//如果此cSocket对象已经处于连接状态,则先关闭
		if(sckStatus==SOCK_CONNECTED) close();
		psock=this;
	}
	psock->m_iHostport=remoteport;
	if(remoteip!=NULL)
		strncpy(psock->m_strHostip,remoteip,19);
	psock->m_strHostip[19]=0;
	psock->m_fd=fd;
	RW_LOG_DEBUG("create cSocket client successfully,connected %s:%d,sock_comm=%d\n",psock->m_strHostip,psock->m_iHostport,psock->m_iComm);
	//获取本地端IP和端口
	addr_len=sizeof(addr);
	if (getsockname(psock->m_fd,(struct sockaddr *) &addr,(socklen_t *)&addr_len)==0)
	{
		if (0==psock->m_iLocalport) psock->m_iLocalport=addr.sin_port;
		ptr=(char *)inet_ntoa(addr.sin_addr);
		if (psock->m_strLocalip[0]==0&&ptr!=NULL)
		{
			strncpy(psock->m_strLocalip,ptr,19);
			psock->m_strLocalip[19]=0;
		}   
		
	}
	
	psock->m_iStatus=SOCK_CONNECTED;
	if (sckStatus==SOCK_LISTEN)
	{
	   
		if(m_client_set.add(psock)<0)
		{
			RW_LOG_WARN("Can not add cSocket client because of limit,server(port:%d) have %d clients.\n",get_localhost_info(),m_client_set.len());
			retv=ELIMIT_SOCK;
		}
		else
		{
			psock->m_pParent=this;
			RW_LOG_DEBUG("server(port:%d) have %d clients in clnt_buf!!!\n",get_localhost_info(),m_client_set.len());

		}

	}//?if (m_status==SOCK_LISTEN)
	if(retv>=0)
	{
		if (psock->start_thread()!=0) {
			RW_LOG_ERROR("starting recv/send thread failed!\n");
			retv=ETHREAD_SOCK;
		}
	}
	
	
	if (retv<0) {
		fd=psock->m_fd;
		psock->m_fd=-1;
		psock->m_iStatus=SOCK_CLOSED;
		if(fd>=0) ::closesocket(fd);
		//删除动态创建的cSocket对象
		if (sckStatus==SOCK_LISTEN) delete psock;
	}
	return retv;
}


/**
 * 连接指定的主机
 * 
 * @param remoteip   主机IP
 * @param remoteport 主机侦听端口
 * 
 * @return <0:发生错误
 *         >=0:连接成功
 * 			返回cSocket对象的句柄,客通过get_pSocket()函数返回cSocket对象的指针
 */
int cSocket::connect(const char * remoteip,int remoteport)
{
    int retv;
	int fd;
	struct sockaddr_in addr;

	if (remoteport<=0||remoteip==NULL||remoteip[0]==0) {
		return EARGS_SOCK;
	}
	if((fd=::socket(AF_INET,SOCK_STREAM,0))>=0)
	{
		addr.sin_family = AF_INET;
		addr.sin_port = htons(remoteport);
		addr.sin_addr.s_addr=inet_addr((const char *)remoteip);  	
		retv=::connect(fd, (struct sockaddr *) &addr, sizeof(addr));
		if(retv==0)
			retv=createClient(fd,remoteip,remoteport);
		else
		{
			retv=ECONN_SOCK;
			::closesocket(fd);
		}
	}
	else
		retv=ESOCKET_SOCK;
	return retv;
}

/**
 * 创建侦听服务cSocket对象
 * 
 * @param iPort 侦听服务端口
 *               >=0启动服务并在指定的端口进行侦听
 * 				如果=0,则系统自动分配侦听服务端口,否则用用户指定的端口
 *               <0,启动服务,但不进行侦听
 * 
 * @return <0:发生错误
 */
int cSocket::listen(int iPort)
{
    int retv=OK_SOCK;
   
	if(m_iStatus!=SOCK_CLOSED) close();
	if (m_fd<0) m_fd=socket(AF_INET,SOCK_STREAM,0);
	if (m_fd<0) return ESOCKET_SOCK;
	if (iPort<0) 
	{
		//create client-server cSocket
		//do not start threads
		m_iComm=0;
		m_iType=0;//tcp
		RW_LOG_DEBUG("Client-Server have started!\n");
	}
	else
	{
		int reuse=1;  
		int addr_len;
		struct sockaddr_in addr;

		m_iLocalport=iPort;
		if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse,sizeof(reuse)) == -1) 
			retv=ESETOPT_SOCK;
		else
		{
			addr.sin_family = AF_INET;
			addr.sin_port = htons(m_iLocalport);
			if (m_strLocalip[0]==0)
			{
				//获取本机IP
				char buf[50];buf[0]=0;
				gethostname(buf,50);
				struct hostent * p=gethostbyname(buf);
				if (p!=NULL&&buf[0]!=0)
					addr.sin_addr=*((struct in_addr *)p->h_addr);
				else
					addr.sin_addr.s_addr=htonl(INADDR_ANY);
				strcpy(m_strLocalip,(char *)inet_ntoa(addr.sin_addr));
			}
			else
				addr.sin_addr.s_addr=inet_addr((const char *)m_strLocalip);
			
			if (bind(m_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) 
				retv=EBIND_SOCK;
			else
			{
				if (::listen(m_fd, 50) == -1) 
					retv=ELISTEN_SOCK;
				else
				{
					//getsockname()函数用于获取一个套接口的名字。它用于一个已捆绑或已连接套接口s,本地地址将被返回。
					//本调用特别适用于如下情况:未调用bind()就调用了connect(),
					//这时唯有getsockname()调用可以获知系统内定的本地地址。
					//在返回时,namelen参数包含了名字的实际字节数。
					//若一个套接口与INADDR_ANY捆绑,也就是说该套接口可以用任意主机的地址,
					//此时除非调用connect()或accept()来连接,否则getsockname()将不会返回主机IP地址的任何信息。
					//除非套接口被连接,WINDOWS套接口应用程序不应假设IP地址会从INADDR_ANY变成其他地址。
					//这是因为对于多个主机环境下,除非套接口被连接,否则该套接口所用的IP地址是不可知的。
					 if (m_iLocalport==0)
					 {
						addr_len=sizeof(addr);
						if (getsockname(m_fd,(struct sockaddr *) &addr,(socklen_t *)&addr_len)==0)
								m_iLocalport=ntohs(addr.sin_port);
						
					 }
					
					m_iComm=1;//server只能收,即接受客户端连接
					m_iType=0;//tcp
					m_iStatus=SOCK_LISTEN;
					retv=m_iLocalport;
					if (start_thread()!=0) 
					{
						close();
						retv=ETHREAD_SOCK;//启动接受和发送数据线程
					}  	
					else
					{
						RW_LOG_DEBUG("Listen-Server have started,port=%d\n",retv);
					}
				}//?if (listen(sock_fd, 50) == -1) else
			}//?if (bind(sock_fd, (struct sockaddr *) &addr, sizeof(addr)) == -1) else
		}//?if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse,sizeof(reuse)) == -1) else
	}//?if (iPort<0) else

	return retv;
}

/**
 * 发送数据到输出缓冲区
 * 
 * @param fmt    格式化字符串
 * 
 * @return 发送数据个数,<0发生错误
 */
int cSocket::send(const char * fmt,...)
{
    char buf[DEFAULT_BUF_SIZE];//vc++ not surpport char[cBuffer::MAX_BUF_SIZE]
	buf[cBuffer::MAX_BUF_SIZE-1]=0;
	va_list args;
	va_start(args,fmt);
	vsnprintf(buf,cBuffer::MAX_BUF_SIZE,fmt,args);
	va_end(args);
	return send(strlen(buf),buf);
}
/**
 * 发送数据到输出缓冲区
 * 
 * @param len    发送数据大小
 * @param buf    发送数据指针
 * 
 * @return 发送数据个数,<0发生错误
 */
int cSocket::send(int len,const char * buf)
{
    int retv=0;
	if (m_fd<0) return EHANDLE_SOCK;
	if (!m_sendThread.status()) return ETHREAD_SOCK;
	if (m_iStatus!=SOCK_CONNECTED) return ECONN_SOCK;
	if (NULL==buf||len<=0) return ENULL_SOCK;
	
	auto_ptr<cBuffer> pbuf(new(nothrow) cBuffer(buf,len));
	if(pbuf.get()!=NULL&&pbuf->len()>0)
	{
		m_out_buf.push (pbuf.release());
		retv=len;
	}
	else
		retv=EMEM_SOCK;
	return retv;
}
/**
 * 发送数据到输出缓冲区
 * 当函数成功时,将更改*ppBuf=NULL,防止调用者释放*ppBuf空间
 * 
 * @param len    发送数据大小
 * @param buf    发送数据指针的指针
 * 
 * @return 发送数据个数,<0发生错误
 */
int cSocket::send(int len,char ** ppBuf)
{
    int retv=0;
	if (m_fd<0) return EHANDLE_SOCK;
	if (!m_sendThread.status()) return ETHREAD_SOCK;
	if (m_iStatus!=SOCK_CONNECTED) return ECONN_SOCK;
	if (NULL==ppBuf||(*ppBuf)==NULL||len<=0) return ENULL_SOCK;
	auto_ptr<cBuffer> pbuf(new(nothrow) cBuffer);
	if(pbuf.get()!=NULL)
	{
		pbuf->set(*ppBuf,len);
		m_out_buf.push (pbuf.release());
		*ppBuf=NULL;
		retv=len;
	}
	else
		retv=EMEM_SOCK;
	return retv;
}
/**
 * 发送数据到输出缓冲区
 * 当函数成功时,将更改*ppBuf=NULL,防止调用者释放*ppBuf空间
 * 
 * @param len    发送数据大小
 * @param buf    发送数据指针的指针
 * 
 * @return 发送数据个数,<0发生错误
 */
int cSocket::send(cBuffer **ppBuf)
{
	int retv=0;
	if (m_fd<0) return EHANDLE_SOCK;
	if (!m_sendThread.status()) return ETHREAD_SOCK;
	if (m_iStatus!=SOCK_CONNECTED) return ECONN_SOCK;
	if (NULL==ppBuf||(*ppBuf)==NULL) return ENULL_SOCK;
	m_out_buf.push(*ppBuf);
	*ppBuf=NULL;
	return retv;
}
/**
 * 接收输入缓冲区中的数据
 * 
 * @param buf     接收缓冲区数据地址空间
 * @param size   接收缓冲区的最大长度
 * 
 * @return 返回接收的数据大小
 */
int cSocket::recv(char *buf,int size)
{
	return getdata(buf,size,0);
}

/**
 * 接收输入缓冲区中的数据
 * 此函数将分配内存接收输入缓冲区的数据,并将分配的内存指针写入ppBuf变量中返回
 * 
 * @param ppBuf   保存接收缓冲区指针的地址指针
 * 
 * @return 返回接收的数据大小
 */
int cSocket::recv(char **ppBuf)
{
	if(ppBuf==NULL) return ENULL_SOCK;
	cBuffer buf;
	cBuffer *ptemp=m_in_buf.peek();
	while(ptemp!=NULL)
	{
		buf.append(ptemp->get(),ptemp->len());
		delete ptemp;
		m_in_buf.pop();
		ptemp=m_in_buf.peek();
	}
	*ppBuf=buf.release();
	return buf.len();
}

/**
 * 接收输入缓冲区中的数据
 * 
 * @param pbuf   接收数据的buffer对象
 * 
 * @return <0,发生错误
 *         返回接收的数据大小
 */
int cSocket::recv(cBuffer *pbuf)
{
	if(pbuf==NULL) return ENULL_SOCK;
	cBuffer *ptemp=m_in_buf.peek();
	while(ptemp!=NULL)
	{
		pbuf->append(ptemp->get(),ptemp->len());
		delete ptemp;
		m_in_buf.pop();
		ptemp=m_in_buf.peek();
	}
	return pbuf->len();
}
/**
 * 往接收缓冲区中插入数据
 * 
 * @param buf    插入数据的指针
 * @param len    插入数据大小
 * 
 * @return 插入数据大小
 *         <0 发生错误
 */
int cSocket::fill(const char * buf,int len)
{
    int retv=0;
	if (NULL==buf||len<=0) return ENULL_SOCK;
	auto_ptr<cBuffer> pbuf(new(nothrow) cBuffer(buf,len));
	if(pbuf.get()!=NULL&&pbuf->len()>0)
	{
		m_in_buf.push (pbuf.release());
		retv=len;
	}
	else
		retv=EMEM_SOCK;
	return retv;
}

/**
 * 将*ppBuf指向的对象压入接收缓冲区堆栈
 * 当函数成功时,将更改*ppBuf=NULL,防止调用者释放*ppBuf空间
 * 
 * @param ppBuf   要压入接收缓冲区的cBuffer对象指针的指针
 * 
 * @return <0,发生错误
 *         插入数据大小
 */
int cSocket::fill(cBuffer **ppBuf)
{
	int retv=0;
    if(ppBuf==NULL||(*ppBuf)==NULL) return ENULL_SOCK;
	retv=(*ppBuf)->len();
	m_in_buf.push(*ppBuf);
	*ppBuf=NULL;
	return retv;
}

//************************************************************************************
//**************************cSocket::clients***************************************************

const int cSocket::clients::MAX_CLIENT_NUM=50;

cSocket::clients::clients()
{
	m_hSocket=0;
}

int cSocket::clients::del(cSocket *psock)
{
	int retv=0;
	if(psock!=NULL)
	{
		m_mutex.lock();
		if(!m_set.empty())
		{
			m_set.erase(psock);
			retv=m_set.size();
		}
		m_mutex.unlock();
		delete psock;
	}
	else
		retv=ENULL_SOCK;
	return retv;
}
int cSocket::clients::remove(cSocket *psock)
{
	int retv=0;
	if(psock!=NULL)
	{
		m_mutex.lock();
		if(!m_set.empty())
		{
			m_set.erase(psock);
			retv=m_set.size();
		}
		m_mutex.unlock();
	}
	else
		retv=ENULL_SOCK;
	return retv;
}
int cSocket::clients::add(cSocket *psock)
{
	int retv=0;
	if (psock!=NULL) {
		m_mutex.lock();
		if(m_set.size()<MAX_CLIENT_NUM)
		{
			if(m_hSocket>=0x7fffffff) m_hSocket=0;
			retv=++m_hSocket;
			m_set[psock]=retv;
		}
		else
			retv=EFULL_SOCK;
		m_mutex.unlock();
	}
	else
		retv=ENULL_SOCK;
	return retv;
}
void cSocket::clients::clear()
{
	cSocket *aPsock[MAX_CLIENT_NUM];
	int i=0;
	m_mutex.lock();
	if(!m_set.empty())
	{
		map<cSocket *,int>::iterator it=m_set.begin();
		for(;it!=m_set.end();it++)
			aPsock[i++]=(*it).first;
		m_set.clear();
	}
	m_mutex.unlock();
	while(i>0)
		delete aPsock[--i];
}
cSocket * cSocket::clients::get(int index)
{
	cSocket *psock=NULL;
	if(index<=0) return NULL;
	m_mutex.lock();
	if(!m_set.empty())
	{
		map<cSocket *,int>::iterator it=m_set.begin();
		for(;it!=m_set.end();it++)
		{
			if(index==(*it).second)
			{
				psock=(*it).first;
				break;
			}
		}
	}
	m_mutex.unlock();
	return psock;
}
cSocket::clients::~clients()
{
	clear();
}









⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -