欢迎访问Ningto's博客

Menu
  • 首页
  • 归档
  • 关于
  • 书签
  • 必应壁纸
  • IT聚合
  • 工具
    • 我的工具列表
    • 我的网盘
    • 必应每日壁纸API
    • Html转Markdown
    • 仙尘光标
Menu

select模型

最后更新 2017-10-24 14:28:26   阅读量 1790

需要注意的是要将listenSock设置为非阻塞模式,这样在while(1)循环中accept才不会被阻塞。同时listenSock也要set到fdread中,如果不这样做的话,select只能监视到客户端的socket,当客户端没有进行任务IO操作的时候select返回值为SOCKET_ERROR会一直进行循环检测,这样是没必要的。

如果有listenSock在fdread中,而又没有新的客户端接入的时候select会阻塞的,只要有一个客户端进行了IO操作或者有新客户端接入select就会变成非阻塞继续进行下面的处理。

在每次FD_SET之前必须FD_ZERO,所以这里使用了一个list来保存SOCKET,在下一次循环的时候重新FD_SET一遍list中的所有SOCKET。


// TcpDemo.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <sstream>
#include <list>

#pragma comment(lib, "Ws2_32.lib")

void handleConn(std::list<SOCKET> &clientSocks, fd_set &fdread);
int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    SOCKET listenSock;
    SOCKADDR_IN serverAddr;
    SOCKADDR_IN clientAddr;
    fd_set fdread;
    int port = 5100;

    WSAStartup(MAKEWORD(2, 2), &wsaData);

    listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (INVALID_SOCKET == listenSock)
    {
        std::cout << "socket failed, errcode:" << WSAGetLastError() << std::endl;
        return 0;
    }
    unsigned long iMode = 1;
    ioctlsocket(listenSock, FIONBIO, &iMode);

    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    int iret = bind(listenSock, (sockaddr*)&serverAddr, sizeof(serverAddr));
    if (SOCKET_ERROR == iret)
    {
        std::cout << "bind failed, errcode:" << WSAGetLastError() << std::endl;
        closesocket(listenSock);
        return 0;
    }
    
    iret = listen(listenSock, SOMAXCONN);
    if ( SOCKET_ERROR == iret)
    {
        std::cout << "listen failed, errcode:" << WSAGetLastError() << std::endl;
        closesocket(listenSock);
        return 0;
    }

    int clientAddrLen = sizeof(clientAddr);

    std::list<SOCKET> clientSocks;
    while (1)
    {
        std::cout << "running" << std::endl;
    
        FD_ZERO(&fdread);
        FD_SET(listenSock, &fdread);
        SOCKET connSock = accept(listenSock, (sockaddr*)&clientAddr, &clientAddrLen);
        if (INVALID_SOCKET == connSock)
        {
            iret = WSAGetLastError();
            if (WSAEWOULDBLOCK == iret)
            {
                std::cout << "waitting ..." << std::endl;
            }
            else
            {
                closesocket(listenSock);
                break;
            }
        }
        else
        {
            clientSocks.push_back(connSock);
        }

        std::list<SOCKET>::iterator iter = clientSocks.begin();
        for ( ; iter!=clientSocks.end(); ++iter)
        {
            FD_SET(*iter, &fdread);
        }

        if (SOCKET_ERROR == select(0, &fdread, NULL, NULL, NULL))
        {
            std::cout << "select failed, errcode:" << WSAGetLastError() << std::endl;
            continue;
        }

        handleConn(clientSocks, fdread);
    }

    system("pause");
    return 0;
}

void handleConn(std::list<SOCKET> &clientSocks, fd_set &fdread)
{
    std::cout << "handle connection" << std::endl; 
    std::list<SOCKET>::iterator iter = clientSocks.begin();
    while (iter != clientSocks.end())
    {
        bool isError = false;
        if (FD_ISSET(*iter, &fdread))
        {
            char buf[1000];
            int irecv = recv(*iter, buf, sizeof(buf), 0);
            int lastError = 0;
            if (SOCKET_ERROR == irecv || 0 == irecv)
            {
                lastError = WSAGetLastError();
                std::cout << "socket:" << *iter << ", erase, lasterror:" << lastError << std::endl;
                isError = true;
            }
            else
            {
                int isend = send(*iter, buf, irecv, 0);
                if (isend < 0)
                {
                    lastError = WSAGetLastError();
                    if (WSAEWOULDBLOCK == lastError)
                    {
                        ::Sleep(100);
                    }
                    else
                    {
                        isError = true;
                        std::cout << "echo error, lasterror:" << lastError << std::endl;
                    }
                }
            }
        }
        if (isError)
        {
            closesocket(*iter);
            clientSocks.erase(iter++);
        }
        else
        {
            ++iter;
        }
    }
}


(转载本站文章请注明作者和出处:泞途 - ningto.com)

下一篇 – WSAAsyncSelect模型
上一篇 – visual stdio不同目录下的文件重名,类重名问题解决方法

  1. Windows

toningto@outlook.com

推荐文章

QProcess 7z.exe 解压进度

IE获取元素样式

标签云

IOS Life Qt Node.js Design Android Tools Product Bug Shell Mobile Go Web Javascript Mac Windows Linux React MQ Others Boost C/C++ MongoDB Tips Python Java Database

推广链接

【腾讯云】云产品限时秒杀,爆款1核2G云服务器,首年99元

多谢支持,用了好几年,服务很稳定支持多设备!

其他

文章RSS

Copyright © 2016 Welcome To Ningto Blog | 鄂ICP备17003086号-2