Linux c++ select 示例

来源:互联网 发布:淘宝货源一件代发网 编辑:程序博客网 时间:2024/06/05 03:32
//主程序#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 1else  //可读的 { 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;}