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;
}