WinsockIO之select模式

1、创建fd_set集合:fd_set ReadSet;

2、对集合进行初始化:FD_ZERO( &ReadSet ) 把集合初始化成空队列.

3、将socket放到集合中:FD_SET(pNew->SocketName, &ReadSet);

4、通过select来查看是否有待决的socket:select(0, &ReadSet, NULL, NULL, NULL);

        select的返回值为处于待决的socket个数

int WSAAPI select( [in] int nfds, [in, out] fd_set *readfds, [in, out] fd_set *writefds, [in, out] fd_set *exceptfds, [in] const timeval *timeout );

        第一个参数nfds可以省略,不影响,通常设为0;

        第二个参数readfds,指向要检查可读性的一组套接字的可选指针。

        第三个参数writefds,指向一组要检查可写性的套接字的可选指针。

        第四个参数exceptfds,指向要检查错误的一组套接字的可选指针。

        第五个参数timeout,select等待的最长时间, 以TIMEVAL结构的形式提供 。将超时参数设置 为null以进行阻塞操作。

5、使用FD_ISSET来判断socket是否在集合中:FD_ISSET(pNew->SocketName, &ReadSet)

6、Select这个FD中对应的readSet集,看是否有读就绪,若有,则是新的连接到来。
7、accept函数返回这个新连接的socket,同时也添加链表的尾部,并写入集合中。
8、循环检测fd中各个Socket中的状态,若监听Socket有读就绪,说明有新连接到来,若是
其他的Socket有读就绪,说明是当前连接有数据到来,注意看基本网络编程都是在accept返回的
的这个新Socket上进行数据传输,服务器自身的socket只用来接收新的连接。

#include <iostream>
using namespace std;

#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")

#include "ClientSocket.h"

int main()
{
    WSADATA wd;

    if (0 != WSAStartup(MAKEWORD(2, 2), &wd))
    {
        WSACleanup();
    }

    SOCKET sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (SOCKET_ERROR == sListen)
    {
        WSACleanup();
    }

    SOCKADDR_IN ListenAddr;
    ListenAddr.sin_family = AF_INET;
    ListenAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    ListenAddr.sin_port = htons(5051);

    if (SOCKET_ERROR == bind(sListen, (const sockaddr*)&ListenAddr, sizeof(ListenAddr)))
    {
        WSACleanup();
    }

    if (SOCKET_ERROR == listen(sListen, 5))
    {
        WSACleanup();
    }

    fd_set ReadSet;

    int nCount = 1;
    char szBuf[255] = "";
    CLIENT* pNew = NULL;
    CreateClient(sListen);//设置头结点为监听

    while (true)
    {
        FD_ZERO(&ReadSet);

        pNew = pHead;

        while(NULL != pNew)
        {
            FD_SET(pNew->SocketName, &ReadSet);
            pNew = pNew->pNext;
        }

        select(0, &ReadSet, NULL, NULL, NULL);//返回值为处于待决状态的socket个数

        pNew = pHead;
        while(NULL != pNew)
        {
            if (FD_ISSET(pNew->SocketName, &ReadSet))
            {
                if (pHead == pNew)//检查监听是否运行,建立与客户端的连接
                {
                    pNew->SocketFlag = 1;
                    CreateClient(accept(sListen, NULL, NULL));//将新建立的socket存在后面
                    cout << "login!!: " << nCount << endl;
                    nCount++;
                    
                }
                else
                {
                    if (SOCKET_ERROR == recv(pNew->SocketName, szBuf, 255, 0))//不能从该socket接收消息,即连接断开了
                    {
                        DeleteClient(pNew->SocketName);
                        break;
                    }
                    cout << szBuf << endl;

                    send(pNew->SocketName, "ok", 3, 0);
                }
            }
            pNew = pNew->pNext;
        }
        
    }

    WSACleanup();
    return 0;
}
#include <iostream>
using namespace std;

#include "ClientSocket.h"

CLIENT* pHead = NULL;

int CreateClient(SOCKET soc)
{
	CLIENT* pNew = new CLIENT;

	if (NULL != pNew)
	{
		pNew->SocketName = soc;
		pNew->SocketFlag = 0;
		pNew->pLast = NULL;
		pNew->pNext = NULL;
	}

	if (NULL == pHead)
	{
		pHead = pNew;
	}
	else
	{
		CLIENT* p = pHead;

		while (NULL != p->pNext)
		{
			p = p->pNext;
		}
		p->pNext = pNew;
		pNew->pLast = p;
	}

	return 0;
}

int DeleteClient(SOCKET soc)
{
	if (NULL == pHead)
	{
		return -1;
	}

	CLIENT* p = pHead;

	while (NULL != p)
	{
		if (p->SocketName == soc)
		{
			if (p != pHead)
			{
				p->pLast->pNext = p->pNext;
			}
			else //头节点
			{
				pHead = p->pNext;
				pHead->pLast = NULL;
			}
			if (NULL != p->pNext)
			{
				p->pNext->pLast = p->pLast;
			}

			closesocket(p->SocketName);
			delete p;
			break;
		}
		p = p->pNext;
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值