非阻塞 TCP协议下多用户的服务器

本文介绍了一个基于Winsock的TCP服务器实现方法,该服务器能够监听并接收客户端的连接请求,并为每个新连接创建独立的线程进行处理。文章详细展示了如何初始化Winsock、设置服务器地址、监听连接以及如何在非阻塞模式下处理客户端数据。
// 一个监听线程, 每当一个新的客户端连接进来时会再创建一个新的线程供连接
#include "stdafx.h"
#include <winsock2.h>
#include <iostream>
#pragma comment( lib, "ws2_32.lib" )

const static int BUF_SIZE = 256;
using namespace std;

#define MAIN_RETURN_ERROR   -1;
#define MAIN_RETURN_NORMAL  0;

DWORD WINAPI AnswerThread( LPVOID lparam );

sockaddr_in addrClient;
int addrClientLen = sizeof( addrClient );

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 sServer ;
    // 创建用于监听的Socket
      sServer = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
      if( INVALID_SOCKET == sServer )
     {
           cout<<"Socket Failed !" <<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 ( sServer, ( const struct sockaddr *)&addrServ , sizeof( SOCKADDR_IN ) );
      if( SOCKET_ERROR == retVal )
     {
           cout<<"bind failed !" <<endl;
           closesocket( sServer );
           WSACleanup();
           return -1;
     }

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

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

      cout<<"TCP Server Start ... ..." <<endl;
      // 循环等待
      while( true )
     {
           SOCKET sClient = accept( sServer, ( sockaddr FAR*)&addrClient , &addrClientLen );
           if( INVALID_SOCKET == sClient )
          {
               int err = WSAGetLastError();
               if( WSAEWOULDBLOCK == err  // 没接到连接请求
              {
                    Sleep( 100 );
                    continue;
              }
               else
              {
                    cout<<"accept failed" <<endl;
                    closesocket( sServer );
                    WSACleanup();
                    return MAIN_RETURN_ERROR ;
              }
          }

          // 接到了创建一个新线程供新的客户端使用
           DWORD dwThreadId ;
           CreateThread( NULL , NULL, AnswerThread, (LPVOID )sClient, 0, & dwThreadId );
     }

      // 最后做一些清理工作
      closesocket( sServer );
      WSACleanup();
      system("pause" );
      return MAIN_RETURN_NORMAL ;
}

DWORD WINAPI AnswerThread( LPVOID lparam )
{
      // 循环接受客户端发送来的请求,直到客户端发送 quit 命令
      char buf [BUF_SIZE];
      int  retVal ;
      SOCKET sClient = (SOCKET)( LPVOID)lparam ;
      while( true )
     {
           ZeroMemory( buf , BUF_SIZE );
           retVal = recv ( sClient, buf, BUF_SIZE , 0 );

           if( SOCKET_ERROR == retVal )
          {
               int err = WSAGetLastError();
               if( WSAEWOULDBLOCK == err )
              {
                    Sleep( 100 );
                    continue;
              }
               else if ( WSAETIMEDOUT == err || WSAENETDOWN == err )   // 网络系统故障
              {
                    cout<<"recv failed !" <<endl;
                    closesocket( sClient );
                    WSACleanup();
                    return MAIN_RETURN_ERROR ;
              }
          }

           SYSTEMTIME st ;
           GetLocalTime( &st );
           char sDateTime [30];
           sprintf( sDateTime , "%4d-%2d-%2d %2d:%2d:%2d", st.wYear , st. wMonth, st .wDay, st.wHour , st. wMinute, st.wSecond );
           cout<<sDateTime <<"  , Recv From Client [ "<< inet_ntoa( addrClient .sin_addr )<<":" <<addrClient. sin_port<<"]: " <<buf<< endl;

           if( 0 == strcmp ( buf, "quit" ) )
          {
               retVal = send ( sClient, "quit", strlen ("quit"), 0 );
               break;
          }
           else
          {
               char msg [BUF_SIZE];
               sprintf( msg , "Message receive - %s ", buf );
               while( true )
              {
                    retVal = send ( sClient, msg, strlen ( msg ), 0 );
                    if( SOCKET_ERROR == retVal )
                   {
                         int err = WSAGetLastError();
                         if( WSAEWOULDBLOCK == err )
                        {
                              Sleep( 100 );
                              continue;
                        }
                         else
                        {
                              cout<<"send failed !" <<endl;
                              closesocket( sClient );
                              WSACleanup();
                              return MAIN_RETURN_ERROR ;
                        }
                   }
                    else
                         break;
              }
          }
     }

      closesocket( sClient );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值