//主程序
#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;
}