Linux c++ select 示例

//主程序
#include <unistd.h>  
#include <iostream>  
#include <sys/socket.h>
#include <sys/select.h>  
#include <arpa/inet.h> 
#include <stdio.h>
#include <string.h>

#include "socket.h"


int main() 
{ 
    int s32ServerSocket = -1; 

    InitServerSocket(s32ServerSocket);
 
     
    //select模型处理过程 
    fd_set  stCheckFdSet,stBakFdSet; 
    //s32AssignFdMax用于记录已分配socket的最大值
	int s32AssignFdMax = s32ServerSocket+1;
	struct timeval stTimeout;
	
	FD_ZERO(&stCheckFdSet);
    FD_ZERO(&stBakFdSet);
    FD_SET(s32ServerSocket, &stBakFdSet);
	
    while (1) 
    { 
       stTimeout.tv_sec = 100;   
       stTimeout.tv_usec = 500000; 
	   //stCheckFdSet 是一个输入输出参数
	   //输入时包含用户感兴趣的描述符
	   //输出时包含活跃的描述符(用户输入集合中的描述符)
	   //所以每次select都要设置fd_set集合
	   stCheckFdSet = stBakFdSet;
        int nRet = ::select(s32AssignFdMax, &stCheckFdSet, NULL, NULL, &stTimeout); 
        if (nRet > 0) 
        { 
            INFO_PRINT("\n"); 
			int s32CurrentFd=0;
            for (s32CurrentFd=0;s32CurrentFd < s32AssignFdMax+1;s32CurrentFd++) 
            { 
                if (FD_ISSET(s32CurrentFd, &stCheckFdSet))//活跃的描述符
                { 
					if(s32ServerSocket == s32CurrentFd)//监听的描述符
					{
						sockaddr_in addrRemote = {0}; 
						socklen_t nAddrLen = sizeof(addrRemote); 
						
						socklen_t NewSocket = ::accept(s32ServerSocket, (sockaddr*)&addrRemote, &nAddrLen); 
						FD_SET(NewSocket, &stBakFdSet); 
						
						if(s32AssignFdMax < NewSocket)
						{
							s32AssignFdMax = NewSocket+1;
						}
						
						INFO_PRINT("accept [%d]!\n",NewSocket); 
					} 
					#if 1
					else  //可读的 
					{ 
						char szContent[256]={0}; 
						
						int nRecv = ::recv(s32CurrentFd, szContent, sizeof(szContent), 0); 
						if (nRecv > 0) 
						{ 
							szContent[nRecv] = '\0'; 
							INFO_PRINT("recv %d:%s\n",nRecv, szContent); 
							::send(s32CurrentFd, szContent, nRecv, 0);  
						} 
						else //异常或关闭的
						{ 
							::close(s32CurrentFd); 
							FD_CLR(s32CurrentFd, &stBakFdSet); 
							INFO_PRINT("close[%d]\n",s32CurrentFd);
						} 
					}
					#endif
				} 
            }
        } 
        else if (nRet == 0)
        { 
            INFO_PRINT("stTimeout!\n"); 
        } 
		else
		{
			 INFO_PRINT("select err!\n"); 
			return -1;; 
		}
    } 
    ::close(s32ServerSocket); //关闭监听描述符
    INFO_PRINT("game over!"); 

    return SUCCESS;
}


//socket部分

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>


#include "socket.h"



static int gs_s32IdleFd = -1;
int InitErrDeal()
{
	/*忽略pipe信号,当客户端关闭socket时,server第一write时会收到RST segment(tcp 传输层)
	server第二次write时,会收到SIGPIPE(brokenpipe)信号,默认处理是退出
	
	TIME_WAIT状态,先close的一端会进入 time_wait状态,内核会在一定的时间内保留socket资源
	(服务器socket通信设计时,让客户端先close)
	*/
	signal(SIGPIPE, SIG_IGN);
	//避免僵尸进程
	signal(SIGCHLD, SIG_IGN);

	gs_s32IdleFd = open("/dev/null", O_RDONLY | O_CLOEXEC);

	return SUCCESS;
}

int ProcessErr(const ERR_INFO_S &stErrInfo)
{
	switch ( stErrInfo.enErrType)
	{

	    case ERR_EMFILE:
	    {
			int *s32pAcceptFd = (int *)(stErrInfo.pvUserData);
			close(gs_s32IdleFd);
			gs_s32IdleFd = accept(*s32pAcceptFd, NULL, NULL);
			close(gs_s32IdleFd);
			gs_s32IdleFd = open("/dev/null", O_RDONLY | O_CLOEXEC);
	        break;
	    }
	    default:
	    {
	        break;
	    }
	}
	
	return SUCCESS;
}

int InitServerSocket(int &s32ServerFd)
{
	int s32Ret = -1;
	//SOCK_NONBLOCK 设置成非阻塞模式,类似于fcnt的F_SETL 的 O_NONBLOCK	
	//SOCK_CLOEXEC,类似于fcnt 的F_GETFD 的 FD_CLOEXEC ,设置进程替换(fork)时,socket处于关闭状态 
	s32ServerFd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP);
	if ( s32ServerFd < 0)
	{
		SHOW_ERR("\n");
		return FAILURE;
	}

	struct sockaddr_in stServerAddr;
	memset(&stServerAddr, 0, sizeof(stServerAddr));
	stServerAddr.sin_family = AF_INET;
	stServerAddr.sin_port = htons(SERVER_PORT);
	stServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	//设置地址的可重复利用,用于socket的快速重启
	int s32OnOff = 1;
	s32Ret= setsockopt(s32ServerFd, SOL_SOCKET, SO_REUSEADDR, &s32OnOff, sizeof(s32OnOff));
	if (s32Ret < 0)
	{
		SHOW_ERR("\n");
		return FAILURE;
	}

	s32Ret = bind(s32ServerFd, (struct sockaddr*)&stServerAddr, sizeof(stServerAddr));
	if (s32Ret < 0)
	{
		SHOW_ERR("\n");
		return FAILURE;
	}

	s32Ret = listen(s32ServerFd, SOMAXCONN);
	if (s32Ret < 0)
	{
		SHOW_ERR("\n");
		return FAILURE;
	}
	return SUCCESS;
	
}

int InitClientSocket(int &s32ClientFd)
{
	int s32Ret = FAILURE;

	s32ClientFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (s32ClientFd < 0)
	{
		SHOW_ERR("\n");
	}

	struct sockaddr_in stServerAddr;
	memset(&stServerAddr, 0, sizeof(stServerAddr));
	stServerAddr.sin_family = AF_INET;
	stServerAddr.sin_port = htons(SERVER_PORT);
	stServerAddr.sin_addr.s_addr = inet_addr(SERVER_IP);

	s32Ret = connect(s32ClientFd, (struct sockaddr*)&stServerAddr, sizeof(stServerAddr));
	if (s32Ret < 0)
	{
		SHOW_ERR("\n");
		return s32Ret;
	}

	struct sockaddr_in stLocalAddr;
	socklen_t addrlen = sizeof(stLocalAddr);
	s32Ret = getsockname(s32ClientFd, (struct sockaddr*)&stLocalAddr, &addrlen);
	if (s32Ret < 0)
	{
		SHOW_ERR("\n");
		return s32Ret;
	}

	SHOW_SOCKADDR_INFO(stLocalAddr);

	return SUCCESS;

}

//客户端
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

#include <iostream>

#include "socket.h"

int main(void)
{
	int s32Socket=-1;

	InitClientSocket(s32Socket);
	
	char acSendBuf[1024] = {0};
	char acRecvBuf[1024] ={0};
	
	while (fgets(acSendBuf, sizeof(acSendBuf), stdin) != NULL)
	{
		::send(s32Socket, acSendBuf, strlen(acSendBuf), 0);
		::recv(s32Socket, acRecvBuf, sizeof(acRecvBuf), 0); 

		fputs(acRecvBuf, stdout);
		memset(acSendBuf, 0, sizeof(acSendBuf));
		memset(acRecvBuf, 0, sizeof(acRecvBuf));
	}

	close(s32Socket);
	
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值