现在的位置: 首页 > 综合 > 正文

用select模式实现TCP和UDP的混合监听

2013年10月03日 ⁄ 综合 ⁄ 共 8515字 ⁄ 字号 评论关闭

// 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;
}

抱歉!评论已关闭.