Windows平台下基于Select模型的服务器

来源:互联网 发布:深度linux系统写python 编辑:程序博客网 时间:2024/05/12 15:09
// 基于 select 模型的socket 编程
#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#pragma comment( lib, "ws2_32.lib" )


using namespace std;

enum
{
      MAIN_RETURN_ERROR           =  -1,
    MAIN_RETURN_NORMAL          =   0,
};


BOOL CreateSocketInformation( SOCKET s );
void FreeSocketInfomation( DWORD Index );


// WSABUF WinSock2  中定义的 结构体,用于保存缓冲区的长度和地址
// struct _WSABUF
// {
//   u_long    len;   // 缓冲区的长度
//   char FAR* buf;   // 缓冲区的指针
// };

const static int DATA_BUF_SIZE = 256;
struct _SOCKET_INFOMATION
{
      char    Buffer [DATA_BUF_SIZE];     // 发送和接收数据缓冲区
      WSABUF  DataBuf ;                   // 定义发送和接收数据缓冲区,保护缓冲区在内的长度和内容
      SOCKET  Socket ;                    // 与客户端进行通信的 socket

      DWORD   BytesSEND ;                 // 保存socket 发送字节数
      DWORD   BytesRECV ;                 // 保存socket 接收字节数
};

typedef _SOCKET_INFOMATION   SOCKET_INFOMATION;
typedef _SOCKET_INFOMATION LPSOCKET_INFOMATION;

const static int BUF_SIZE = 256;

DWORD TotalSockets = 0;
LPSOCKET_INFOMATION SocketArray[ FD_SETSIZE];



int _tmain( int argc , _TCHAR* argv[])
{
      // 初始化Winsock 2.2
      WSADATA wsaData ;
      if( WSAStartup ( MAKEWORD( 2, 2 ), & wsaData ) != 0 )
     {
           cout<<"WSAStartup 无法初始化 !" <<endl ;
           return MAIN_RETURN_ERROR ;
     }

      // 通过WinSock 实现网络通信
      SOCKET AcceptSocket ;
      SOCKET ListenSocket ;
    // 创建用于监听的Socket
      ListenSocket = WSASocket ( AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED );
      if( INVALID_SOCKET == ListenSocket )
     {
           cout<<"Socket Failed !" <<" Reson:"<< WSAGetLastError()<<endl ;
           WSACleanup();
           return MAIN_RETURN_ERROR ;
     }

      // 设置服务器Socket 地址
      SOCKADDR_IN addrServ ;
      addrServ.sin_family   = AF_INET;
      addrServ.sin_port     = htons( 9990 );   // 服务器端口号
      addrServ.sin_addr .S_un. S_addr = htonl ( INADDR_ANY );

      // 绑定
      int    retVal ;
      retVal = bind ( ListenSocket, ( const struct sockaddr *)&addrServ , sizeof( SOCKADDR_IN ) );
      if( SOCKET_ERROR == retVal )
     {
           cout<<"bind failed !" <<"   Reson: "<< WSAGetLastError()<<endl ;
           closesocket( ListenSocket );
           WSACleanup();
           return -1;
     }

      // 监听
      retVal = listen ( ListenSocket, 5 );
      if( SOCKET_ERROR == retVal )
     {
           cout<<"listen failed !" <<" Reson:"<< WSAGetLastError()<<endl ;
           closesocket( ListenSocket );
           WSACleanup();
           return -1;
     }

      // 设置socket 其为非阻塞模式 , argp 设为非零值
      int iModel = 1; 
      retVal = ioctlsocket ( ListenSocket, FIONBIO, (u_long FAR* )&iModel );
      if( SOCKET_ERROR == retVal )
     {
           cout<<"ioctlsocket failed  Reson :"<< WSAGetLastError()<<endl ;
           WSACleanup();
           return MAIN_RETURN_ERROR ;
     }

      //
      CreateSocketInformation ( ListenSocket );

      cout<<"TCP Server Start ... ..." <<endl;
      // 循环等待
      FD_SET WriteSet ;
      FD_SET ReadSet ;
      DWORD  Total = 0;
      DWORD  SendBytes , RecvBytes;
      while( true )
     {
           FD_ZERO( &ReadSet );
           FD_ZERO( &WriteSet );
           FD_SET( ListenSocket , &ReadSet );
           for( DWORD i = 0; i < TotalSockets ; ++i )
          {
               LPSOCKET_INFOMATION SocketInfo = SocketArray [i];
               FD_SET( SocketInfo ->Socket, & WriteSet );
               FD_SET( SocketInfo ->Socket, & ReadSet  );
          }

           if( ( Total = select( 0, & ReadSet, &WriteSet , NULL, NULL ) ) == SOCKET_ERROR )
          {
               cout<<"Select Return with Error "<< WSAGetLastError()<<endl ;
               return -1;
          }
          
           for( DWORD i = 0; i < TotalSockets ; ++i )
          {
               // SocketInfo 为当前要处理的信息
               LPSOCKET_INFOMATION SocketInfo = SocketArray [i];
               // 判断当前socket 的可读性,即是否有接入的连接请求可以接收数据
               if( FD_ISSET ( SocketInfo-> Socket, &ReadSet ) )
              {
                    // 对于监听来说,可读表示有新的连接请求
                    if( SocketInfo ->Socket == ListenSocket )
                   {
                         Total--;
                         // 接受连接请求,与客户端进行通信
                         if( ( AcceptSocket = accept( ListenSocket , NULL, NULL ) ) != INVALID_SOCKET )
                        {
                              int NonBlock = 1;
                              if( ioctlsocket ( AcceptSocket , FIONBIO, ( u_long FAR * )&NonBlock) == SOCKET_ERROR )
                             {
                                   cout<<"ioctlsocket() failed with error "<< WSAGetLastError()<<endl ;
                                   return -1;
                             }

                              if( CreateSocketInformation ( AcceptSocket ) == FALSE )
                                   return -1;
                        }
                         else
                        {
                              if( WSAGetLastError () != WSAEWOULDBLOCK )
                             {
                                   cout<<"accept failed with error "<< WSAGetLastError()<<endl ;
                                   return -1;
                             }
                        }
                   }
                    // 有新的数据到达
                    else
                   {
                         // 如果当前在ReadSet集合中,表明有数据可读
                         if( FD_ISSET ( SocketInfo-> Socket, &ReadSet ) )
                        {
                             -- Total;
                              memset( SocketInfo ->Buffer, ' ', DATA_BUF_SIZE );
                              SocketInfo->DataBuf .buf = SocketInfo ->Buffer;
                              SocketInfo->DataBuf .len = DATA_BUF_SIZE ;

                              // 接收数据
                              DWORD Flags = 0;
                              if( WSARecv ( SocketInfo ->Socket, &( SocketInfo->DataBuf ), 1, &RecvBytes , &Flags, NULL, NULL ) == SOCKET_ERROR )
                             {
                                   if( WSAEWOULDBLOCK != WSAGetLastError () )
                                  {
                                       cout<<"WSARecv failed with error "<< WSAGetLastError()<<endl ;
                                        FreeSocketInfomation ( i );
                                  }

                                   continue;
                             }
                              else
                             {
                                   SocketInfo->BytesRECV = RecvBytes ;
                                   if( RecvBytes == 0 )
                                  {
                                        FreeSocketInfomation ( i );
                                       continue;
                                  }
                                   else
                                  {
                                        cout<<SocketInfo ->DataBuf. buf<<endl ;
                                  }
                             }
                        }
                   }
              }
               else
              {
                    // 发送数据
                    if( FD_ISSET ( SocketInfo-> Socket, &WriteSet ) )
                   {
                        -- Total;
                         SocketInfo->DataBuf .buf = SocketInfo ->Buffer + SocketInfo->BytesSEND ;
                         SocketInfo->DataBuf .len = SocketInfo ->BytesRECV - SocketInfo->BytesSEND ;
                         if( SocketInfo ->DataBuf. len > 0 )
                        {
                              if WSASend ( SocketInfo ->Socket, &( SocketInfo->DataBuf ), 1, &SendBytes , 0, NULL, NULL ) == SOCKET_ERROR )
                             {
                                   if( WSAGetLastError () != WSAEWOULDBLOCK )
                                  {
                                       cout<<"WSASend failed with error "<< WSAGetLastError()<<endl ;
                                        FreeSocketInfomation ( i );
                                  }

                                   continue;
                             }
                              else
                             {
                                   SocketInfo->BytesSEND += SendBytes ;
                                   if( SocketInfo ->BytesSEND == SocketInfo->BytesRECV )
                                  {
                                        SocketInfo->BytesRECV = 0;
                                        SocketInfo->BytesSEND = 0;
                                  }
                             }
                        }
                   }
              }
          }
     }
          
      // 最后做一些清理工作
      closesocket( ListenSocket );
      closesocket( AcceptSocket );
      WSACleanup();
      system("pause" );
      return MAIN_RETURN_NORMAL ;
}



// 创建 SOCKET
BOOL CreateSocketInformation( SOCKET s )
{
      LPSOCKET_INFOMATION SI ;
      // SI 分配空间
      if( ( SI = (LPSOCKET_INFOMATION) GlobalAlloc( GPTR , sizeof ( SOCKET_INFOMATION ) ) ) == NULL )
     {
           cout<<"GlobalAlloc Failed with Error "<< GetLastError();
           return FALSE ;
     }

      SI->Socket        = s;
      SI->BytesSEND     = 0;
      SI->BytesRECV     = 0;

      SocketArray[TotalSockets ] = SI;
     ++ TotalSockets;

      return TRUE ;
}

void FreeSocketInfomation( DWORD Index )
{
      LPSOCKET_INFOMATION SI = SocketArray[ Index];
      DWORD i ;
      closesocket( SI ->Socket );
      GlobalFree( SI );
      for( i = Index; i < TotalSockets ; ++i )
           SocketArray[i ] = SocketArray[ i+1];

     -- TotalSockets;
}



客户端1:


客户端2




服务器:

没有实现收到 服务端把数据发回客户端。
0 0
原创粉丝点击