// SelectTestServer.cpp : 定义控制台应用程序的入口点。
////////////////////////////////////////////
//
// TCP UDP复用Server select非阻塞模式
// IP: 127.0.0.1
// TCP PORT: 5001
// UDP PORT: 5000
////////////////////////////////////////////
#include "stdafx.h"
#include <WINSOCK2.H>
#pragma comment ( lib, "ws2_32" )
#define LISTEN_IP "127.0.0.1"
#define LISTEN_TCP_PORT 5001 //TCP监听端口
#define LISTEN_UDP_PORT 5000 //UDP监听端口
#define DEFAULT_BUFF 256
#define MAX_LISTEN 5 //最多可同时连接的客户端数量
int g_fd_ArrayC[MAX_LISTEN] = {0}; //处理所有的待决连接
char recvBuff[DEFAULT_BUFF] = "\0";
char responseBuff[DEFAULT_BUFF] = "\0";
char noresponseBuff[DEFAULT_BUFF] = {"server connection is full"};
int g_nRes = 0;
int g_nConnNum = 0;//当前的客户端连接数
void ClientSocketAdd(fd_set FAR * set) //将服务器接收到的客户端socket添加到select监听中
{
for( int nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi )
{
if( g_fd_ArrayC[nLoopi] !=0 )
{
printf("-LOOPI: 待决SOCKET: %d\n",g_fd_ArrayC[nLoopi] );
FD_SET(g_fd_ArrayC[nLoopi], set );
}
}
}
void CheckActiveSocket(fd_set FAR * set) //轮询查看是否有select监听的socket有数据写入,并作出回应
{
printf("-查找可用的SOCKET\n");
for( int nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi )
{
if( FD_ISSET(g_fd_ArrayC[nLoopi], set) )
{
memset( recvBuff, 0 ,sizeof(recvBuff) );
g_nRes = recv( g_fd_ArrayC[nLoopi], recvBuff, sizeof(recvBuff)-1, 0 );
if( g_nRes <= 0 )
{
printf("-Client Has Closed.\n");
closesocket( g_fd_ArrayC[nLoopi] );
//将已经关闭的SOCKET从FD集中删除
FD_CLR( g_fd_ArrayC[nLoopi], set );
g_fd_ArrayC[nLoopi] = 0;
//g_fd_ResponseCount[nLoopi] = 0;//客户socket关闭,则不再重复回复信息
--g_nConnNum;
}
else
{
recvBuff[g_nRes] = '\0';
char* ptrStart;
char* ptrCurrent;
char tempbuffer[1000]="\0";
char noteId[5]="\0"; //节点ID
char result[3]="OK"; //返回结果
int messageLen=0;
int resultCount=5; //从接受到的报文中提取需要定时随机回复的次数
char s_messageLen[5]="\0";
printf("-Recvied: %s\n", recvBuff);
ptrStart=recvBuff;
ptrCurrent=recvBuff;
ptrCurrent+=4;//移动到ID字段
strncpy(noteId,ptrCurrent,4);
ptrCurrent+=4;//移动到ID字段+=4;//移动到负载长度字段
strncpy(s_messageLen,ptrCurrent,4);
messageLen=atoi(s_messageLen);
printf("messageLen= %d\n",messageLen);
printf("recvBuff= %d\n",strlen(recvBuff));
if(messageLen==(strlen(recvBuff)-14))
{
memset(responseBuff,0,DEFAULT_BUFF);
memset(tempbuffer,0,sizeof(tempbuffer));
sprintf(tempbuffer,"<?xml version=\"1.0\" encoding=\"utf-8\"?><FlowSchedule><Schedule ID=\"%s\" Result=\"%s\"></FlowSchedule>",noteId,result);
strncpy(responseBuff,recvBuff,8);
sprintf(responseBuff+8,"%04d%s00",strlen(tempbuffer),tempbuffer);
send( g_fd_ArrayC[nLoopi], responseBuff, strlen(responseBuff), 0 );
//g_fd_ResponseCount[nLoopi]=resultCount;
srand((unsigned)time(NULL));
for(int i=0;i<resultCount-1;i++)
{
printf("response i=%d \n",i);
memset(responseBuff,0,DEFAULT_BUFF);
int resultRand=rand()%2;
if(resultRand==0)
{
sprintf(tempbuffer,"<?xml version=\"1.0\" encoding=\"utf-8\"?><FlowSchedule><Schedule ID=\"%s\" Result=\"%s\"></FlowSchedule>",noteId,"OK");
strncpy(responseBuff,recvBuff,8);
sprintf(responseBuff+8,"%04d%s00",strlen(tempbuffer),tempbuffer);
send( g_fd_ArrayC[nLoopi], responseBuff, strlen(responseBuff), 0 );
printf("response count=%d %s \n",i,responseBuff);
}
else if(resultRand==1)
{
sprintf(tempbuffer,"<?xml version=\"1.0\" encoding=\"utf-8\"?><FlowSchedule><Schedule ID=\"%s\" Result=\"%s\"></FlowSchedule>",noteId,"Fail");
strncpy(responseBuff,recvBuff,8);
sprintf(responseBuff+8,"%04d%s00",strlen(tempbuffer),tempbuffer);
send(g_fd_ArrayC[nLoopi], responseBuff, strlen(responseBuff), 0 );
printf("response count=%d %s \n",i,responseBuff);
break;
}
else
{
printf("rand() error! \n");
}
Sleep(5000);
}
}
else
{
char responseErrorBuff[DEFAULT_BUFF] = "send data has a error format";
send( g_fd_ArrayC[nLoopi], responseErrorBuff, strlen(responseErrorBuff), 0 );
}
}
}
}//for( nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi )
}
int _tmain(int argc, _TCHAR* argv[])
{
WSAData wsData;
SOCKET sTcpListen;
SOCKET sUdpListen;
SOCKET sClient;
SOCKADDR_IN addrListen;
SOCKADDR_IN addrTcpClient;
SOCKADDR_IN addrUdpClient;
int addrUdpClientLen =sizeof(addrUdpClient);
int addrTcpClientLen = sizeof(addrTcpClient);
printf(">>>>>TCP 服务器端启动<<<<<<\n");
WSAStartup(MAKEWORD(2,2), &wsData);
//----------------------------------
//创建一个socket的TCP服务器监听端口
printf("-创建一个TCP SOCKET\n");
sTcpListen = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if(sTcpListen==INVALID_SOCKET)
{
printf("!!! socket failed: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("-设定TCP服务器监听端口\n");
addrListen.sin_family = AF_INET;
addrListen.sin_addr.S_un.S_addr = inet_addr(LISTEN_IP);
addrListen.sin_port = htons( LISTEN_TCP_PORT );
printf("-绑定SOCKET与指定监听端口: %s:%d\n", inet_ntoa(addrListen.sin_addr), ntohs(addrListen.sin_port));
g_nRes = bind( sTcpListen, (const sockaddr*)&addrListen, sizeof(addrListen) );
if( g_nRes == SOCKET_ERROR )
{
printf("!!! bind failed: %d\n", WSAGetLastError());
closesocket( sTcpListen );
WSACleanup();
return -1;
}
printf("-监听端口\n");
g_nRes = listen( sTcpListen, MAX_LISTEN );
if( g_nRes == SOCKET_ERROR )
{
printf("!!! listen failed: %d\n", WSAGetLastError());
closesocket( sTcpListen );
WSACleanup();
return -1;
}
//----------------------------------
//创建一个socket的UDP服务器监听端口
printf("-创建一个UDP SOCKET\n");
sUdpListen = socket( AF_INET, SOCK_DGRAM, 0);
if(sUdpListen==INVALID_SOCKET)
{
printf("!!! socket failed: %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("-设定UDP服务器监听端口\n");
addrListen.sin_family = AF_INET;
addrListen.sin_addr.S_un.S_addr = inet_addr(LISTEN_IP);;
addrListen.sin_port = htons( LISTEN_UDP_PORT );
printf("-绑定SOCKET与指定监听端口: %s:%d\n", inet_ntoa(addrListen.sin_addr), ntohs(addrListen.sin_port));
g_nRes = bind( sUdpListen, (const sockaddr*)&addrListen, sizeof(addrListen) );
if( g_nRes == SOCKET_ERROR )
{
printf("!!! bind failed: %d\n", WSAGetLastError());
closesocket( sUdpListen );
WSACleanup();
return -1;
}
/////////////////////////////
// 非阻塞模式设定TCP
/////////////////////////////
DWORD nMode = 1;
g_nRes = ioctlsocket( sTcpListen, FIONBIO, &nMode );
if( g_nRes == SOCKET_ERROR )
{
printf("!!! ioctlsocket failed: %d\n", WSAGetLastError());
closesocket( sTcpListen );
WSACleanup();
return -1;
}
/////////////////////////////
// 非阻塞模式设定UDP
/////////////////////////////
nMode = 1;
g_nRes = ioctlsocket( sUdpListen, FIONBIO, &nMode );
if( g_nRes == SOCKET_ERROR )
{
printf("!!! ioctlsocket failed: %d\n", WSAGetLastError());
closesocket( sUdpListen );
WSACleanup();
return -1;
}
printf("-设置服务器端模式: %s\n", nMode==0? "阻塞模式":"非阻塞模式");
printf("-开始准备接受连接\n");
fd_set fdRead;
//fd_set fdWrite;
timeval tv={10,0}; //设定select每次的轮询时间
int nLoopi = 0;
while(true)
{
printf("-select 开始\n");
FD_ZERO(&fdRead);
//FD_ZERO(&fdWrite);
FD_SET( sTcpListen, &fdRead );
FD_SET( sUdpListen, &fdRead );
//将待决的连接SOCKET放入fdRead集中进行select监听
ClientSocketAdd( &fdRead);
/* 调用select模式进行监听*/
g_nRes = select( 0, &fdRead, NULL, NULL, &tv );
if( g_nRes == 0 )
{
printf("-!!! select timeout: %d sec\n",tv.tv_sec);
continue; //继续监听
}
else if( g_nRes < 0 )
{
printf("!!! select failed: %d\n", WSAGetLastError());
break;
}
/* 检查所有的可用SOCKET*/
CheckActiveSocket(&fdRead);
//检查UDP socket连接
if(FD_ISSET( sUdpListen, &fdRead))
{
//对UDPsocket的处理
char buffer[1024]="\0";
char bufferResponse[10]="HBPRS";
printf("waiting for message addrUdpClient others-------------\n");
if (recvfrom(sUdpListen,buffer,sizeof(buffer),0,(struct sockaddr*)&addrUdpClient,&addrUdpClientLen)!=SOCKET_ERROR)
{
printf("Received datagram addrUdpClient %s--%s\n",inet_ntoa(addrUdpClient.sin_addr),buffer);
if(0==strncmp("HBPRQ",buffer,5))
{
////给cilent发信息
sendto(sUdpListen,bufferResponse,sizeof(bufferResponse),0,(struct sockaddr*)&addrUdpClient,addrUdpClientLen);
}
else
{
////给cilent发信息
sendto(sUdpListen,buffer,sizeof(buffer),0,(struct sockaddr*)&addrUdpClient,addrUdpClientLen);
}
}
}
//检查是否为新的连接进入
if( FD_ISSET( sTcpListen, &fdRead) )
{
printf("-发现一个新的客户连接\n");
sClient = accept( sTcpListen, (sockaddr*)&addrTcpClient, &addrTcpClientLen );
if( sClient == WSAEWOULDBLOCK )
{
printf("!!! 非阻塞模式设定 accept调用不正\n");
continue;
}
else if( sClient == INVALID_SOCKET )
{
printf("!!! accept failed: %d\n", WSAGetLastError());
continue;
}
//新的连接可以使用,查看待决处理队列
if( g_nConnNum<MAX_LISTEN )
{
for(nLoopi=0; nLoopi<MAX_LISTEN; ++nLoopi)
{
if( g_fd_ArrayC[nLoopi] == 0 )
{//添加新的可用连接
g_fd_ArrayC[nLoopi] = sClient;
break;
}
}
++g_nConnNum;
printf("-新的客户端信息:[%d] %s:%d\n", sClient, inet_ntoa(addrTcpClient.sin_addr), ntohs(addrTcpClient.sin_port));
}
else
{
printf("-服务器端连接数已满: %d\n", sClient);
send( sClient, noresponseBuff, strlen(noresponseBuff), 0 );
closesocket( sClient );
}
}//if( FD_ISSET( sTcpListen, &fdRead) )
}//while(true)
printf("-关闭服务器端SOCKET\n");
closesocket( sTcpListen );
closesocket( sUdpListen );
WSACleanup();
return 0;
}