select模型的原理是在指定的socket 的数组中轮询的采集是否可写、可读、有异常的信息,然后将可以操做的套接字 保存在指定的数组中。
// selectsocket.cpp : 定义控制台应用程序的入口点。
//
//socket select 模型 缺点实时性不太强
#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
struct clientInfo{
SOCKET connectSock;
SOCKADDR_IN clientAddr;
};
clientInfo _arrayClientInfo[FD_SETSIZE];
int _curCount = 0;
DWORD WINAPI WorkThread(LPVOID lpParameter)
{
//接受和回复 消息
FD_SET readAry;
FD_ZERO(&readAry);
//超时时间
timeval outTime;
outTime.tv_sec = 5;
outTime.tv_usec = 0;
char buf[1024] ={0};
while(true)
{
FD_ZERO(&readAry);
for(int i = 0;i < _curCount;i++)
{
if(_arrayClientInfo[i].connectSock != -1)
{
FD_SET(_arrayClientInfo[i].connectSock,&readAry);
}
}
int rtValue = select(0,&readAry,NULL,NULL,&outTime);
if(rtValue != 0 && rtValue != SOCKET_ERROR)
{
//输出收到的数据并且回复
for(int i = 0; i< _curCount;i++)
{
if(FD_ISSET(_arrayClientInfo[i].connectSock,&readAry))
{
if(0 == recv(_arrayClientInfo[i].connectSock,buf,sizeof(buf),0))
{
_arrayClientInfo[i].connectSock = -1;
continue;
}
cout << "recv data by:" << inet_ntoa(_arrayClientInfo[i].clientAddr.sin_addr) <<" " << buf << endl;
send(_arrayClientInfo[i].connectSock,"hello",sizeof("hello"),0);
}
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
//1 初始化windows socket库
WSADATA wsaData;
if(0 != WSAStartup(MAKEWORD(2,2),&wsaData))
{
cout << "WSAStartup failed" <<endl;
return -1;
}
//2 创建套接字
SOCKET listenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(INVALID_SOCKET == listenSocket)
{
cout << "socket failed errcode:" << WSAGetLastError() << endl;
return -1;
}
//3 绑定套接字
SOCKADDR_IN serAddr;
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //将字符串转成数字并且是网络字节序
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8000);
if(0 !=bind(listenSocket,(sockaddr*)&serAddr,sizeof(sockaddr)))
{
cout << "bind failed errcode:" << WSAGetLastError() << endl;
return -1;
}
//4 监听
if(SOCKET_ERROR == listen(listenSocket,10))
{
cout << "listen failed errcode:" << WSAGetLastError() << endl;
return -1;
}
cout << "开启监听" << endl;
//创建线程以应答 客户端的请求
CreateThread(NULL,NULL,WorkThread,NULL,0,NULL);
//接受链接请求
SOCKET connectSock;
SOCKADDR_IN clientAddr;
int iSizeofAddr = sizeof(sockaddr);
while (_curCount < FD_SETSIZE)
{
connectSock = accept(listenSocket,(sockaddr*)&clientAddr,&iSizeofAddr);
if(INVALID_SOCKET != connectSock)
{
//建立连接成功
_arrayClientInfo[_curCount].clientAddr = clientAddr;
_arrayClientInfo[_curCount].connectSock = connectSock;
_curCount++;
}
}
//当前达到64 个链接的时候 关闭 监听套接字 本程序只接受64个连接
closesocket(listenSocket);
cout << "链接已满" << endl;
system("pause");
return 0;
}
缺点是 需要不断的轮询,处理不够及时。
客户端代码:
// sockclient.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2),&wsaData);
SOCKADDR_IN serAddr;
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8000);
SOCKET clientSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
connect(clientSocket,(sockaddr*)&serAddr,sizeof(sockaddr));
char buf[1024] ={0};
send(clientSocket,"hello server",sizeof("hello server"),0);
recv(clientSocket,buf,sizeof(buf),0);
cout << buf << endl;
closesocket(clientSocket);
WSACleanup();
system("pause");
return 0;
}