winsock i/o的select模型的学习测试

#include<winsock2.h>
#include<stdio.h>
#include<windows.h>
#pragma comment(lib,"WS2_32.lib")

BOOL InsertSock(SOCKET* pSock,  SOCKET sock)
{
          for   (int  nIndex  =  0;  nIndex  <  FD_SETSIZE - 1;  nIndex++)
         {
                                     if   (pSock[nIndex]  ==  INVALID_SOCKET)
                  {
                          pSock[nIndex] = sock;
                          break;
                  }
          }
 
          if   (nIndex == FD_SETSIZE - 1)
                 return FALSE;
     
          return TRUE;
 }

 

int main(int argc, char* argv[])
{
 
WSADATA wsaData;
WORD sockVersion=MAKEWORD(2,0);
WSAStartup(sockVersion,&wsaData);

SOCKET clientsockarray[FD_SETSIZE - 1];
SOCKET s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(s==INVALID_SOCKET)
{
  printf(" Failed socket()/n");
  WSACleanup();
  return 0;
}

sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(8888);
sin.sin_addr.S_un.S_addr=INADDR_ANY;

if(bind(s,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)
{
  printf(" Failed bind() %d/n",GetLastError());
  WSACleanup();
  return 0;
}

if(listen(s,63)==SOCKET_ERROR)
{
  printf(" Failed listen()/n");
  WSACleanup();
  return 0;
}

for (int i=0;i < 64; i++)
{
  clientsockarray[i] = INVALID_SOCKET;
}


sockaddr_in remoteAddr;
int nAddrLen=sizeof(remoteAddr);

//char szText[]="Hello World!";
FD_SET fd;
FD_ZERO(&fd);
TIMEVAL tv={30,0};
FD_SET(s,&fd);

printf("server start:%d/n",GetLastError());
int num=0;
while(TRUE)
{
 int nResult;
    nResult = select(0,&fd, NULL,NULL,&tv);
 if (nResult == SOCKET_ERROR)
 {
  printf("select failed /n");
  continue;
 }
 /*
 if (nResult > 0)
 {
  printf("dddddddddd/n");
 }
 */

 if(FD_ISSET(s,&fd))
 {
 SOCKET client;
 client=accept(s,(SOCKADDR*)&remoteAddr,&nAddrLen);
 if (client == INVALID_SOCKET)
 {
  printf("client connect fail %d",GetLastError());
  continue;
 }
 if(!InsertSock(clientsockarray,client))
 {
  printf("³¬¹ý×î´óSOCKET/n");
  closesocket(client);
  continue;
 }
 FD_SET(client,&fd);
 }
  // Öð¸ö´¦Àí´¦ÓÚ´ý¾ö״̬µÄÌ×½Ó×Ö

nResult = select(0,&fd, NULL,NULL,&tv);
if (nResult == SOCKET_ERROR)
{
 printf("select failed /n");
 continue;
}

for (int nIndex  =  0;  nIndex  <=  FD_SETSIZE - 1;  nIndex++)
 {
  if(FD_ISSET(clientsockarray[nIndex], &fd))
  {  
   //printf("aaaa/n");
   char buffer[256];
   int nRet  =  recv(clientsockarray[nIndex],  buffer,  sizeof(buffer),  0);
   if  (nRet  ==  0  ||  nRet  ==  SOCKET_ERROR)
   {
    closesocket(clientsockarray[nIndex]);
    clientsockarray[nIndex] = INVALID_SOCKET;
    continue;       // ¼ÌÐø´¦ÀíÌ×½Ó×Ö¾ä±úÊý×éÖеÄÆäËüÌ×½Ó×Ö
   }
   // ½«½ÓÊܵ½µÄÊý¾Ý½øÐд¦Àí,´Ë´¦Ö»½«ÆäÊä³ö
   //char buffer[256];
   //recv(clientsockarry[nIndex],buffer,256);
   printf("has recv data from socket %d : %s",i, buffer);
   printf(" num:%d/n",++num);
  }
}


}

closesocket(s);
WSACleanup();
return 0;

}

 

附一个例子,,

下面这段代码是一个建立在SELECT这是I/O模型的多连接应用。能正常工作。
但有些问题。就是在接受2或更多连接后,当接收这些连接发送的数据时总发生,不稳定的情况。
例如;
当接受3个连接后。
1连接发送数据 11111。
显示 11111。
2连接发送 22222。
显示 22222
空跑一个。
3连接发送 33333。
显示则是
3
3
3
3
3跑了5回,是分着接收的数据。

我不明白为什么,到后来程序变得不稳定了?
为什么一条数据总要,一个字节一个字节的接送?
为什么总发送空接收的现象?
是哪个地方没处理好呢?

代码如下:

//    select I/O模型


#include <stdio.h>
#include <winsock2.h>

#pragma comment(lib, "WS2_32")

int ret;

int main()
{
    USHORT nPort = 12345;    // 此服务器监听的端口号

    WSADATA wsaData;

    if(WSAStartup(0x0202,&wsaData) != 0)
    {
        printf("wsastartup  error !/n");
        getchar();
        return 0;
    }

    // 创建监听套节字
    SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    
    sockaddr_in sin;
    
    sin.sin_family = AF_INET;
    sin.sin_port = htons(nPort);
    sin.sin_addr.S_un.S_addr = INADDR_ANY;

    // 绑定套节字到本地机器
    if(bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
    {
        printf(" Failed bind() /n");
        return 0;
    }
    
    if(listen(sListen, 5))
    {
        printf("listen error !/n");
        getchar();
        return 0;
    }

    //-------------------------------------------------看来这个模式的设置有必要的。
    ULONG NonBlock = 1;
    if (ioctlsocket(sListen, FIONBIO, (u_long *)&NonBlock) == SOCKET_ERROR)
    {
        printf("ioctlsocket() failed with error %d/n", WSAGetLastError());
        getchar();
        return 0;
    }
    //----------------------------------------------------

        // select模型处理过程
    // 1)初始化一个套节字集合fdSocket,添加监听套节字句柄到这个集合
    fd_set fdSocket;        // 所有可用套节字集合
    FD_ZERO(&fdSocket);
    FD_SET(sListen, &fdSocket);
    
    while(TRUE)
    {
        ret = printf("/n big while -----------------------!/n");
        
        // 2)将fdSocket集合的一个拷贝fdRead传递给select函数,
        // 当有事件发生时,select函数移除fdRead集合中没有未决I/O操作的套节字句柄,然后返回。
        fd_set fdRead = fdSocket;
        int nRet = select(0, &fdRead, NULL, NULL, NULL);
        
        if(nRet > 0)
        {
            // 3)通过将原来fdSocket集合与select处理过的fdRead集合比较,
            // 确定都有哪些套节字有未决I/O,并进一步处理这些I/O。
            for(int i=0; i<(int)fdSocket.fd_count; i++)
            {
                ret = printf("/n big for !/n");
                if(FD_ISSET(fdSocket.fd_array[i], &fdRead))
                {
                    if(fdSocket.fd_array[i] == sListen)        // (1)监听套节字接收到新连接
                    {
                        if(fdSocket.fd_count < FD_SETSIZE)
                        {
                            sockaddr_in addrRemote;
                            int nAddrLen = sizeof(addrRemote);
                            SOCKET sNew = ::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen);
                            FD_SET(sNew, &fdSocket);
                            printf("接收到连接(%s)/n", ::inet_ntoa(addrRemote.sin_addr));
                        }
                        else
                        {
                            printf(" Too much connections! /n");
                            continue;
                        }
                    }
                    else
                    {
                        char szText[256];
                        int nRecv = ::recv(fdSocket.fd_array[i], szText, sizeof(szText), 0);
                        if(nRecv > 0)                        // (2)可读
                        {
                            szText[nRecv] = '/0';
                            printf("接收到数据:%s /n", szText);
                        }
                        else                                // (3)连接关闭、重启或者中断
                        {
                            ::closesocket(fdSocket.fd_array[i]);
                            FD_CLR(fdSocket.fd_array[i], &fdSocket);
                        }
                    }
                }
            }
        }
        else
        {
            printf(" Failed select() /n");
            break;
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值