/********************************************************************
created: 2016/09/23
created: 23:9:2016 9:04
filename: D:\code\SocketClassify\SocketClassify\TCPServ_SelectModel.h
file path: D:\code\SocketClassify\SocketClassify
file base: TCPServ_SelectModel
file ext: h
author: singebogo
purpose: 选择模型:Select(选择)模型是Winsock中最常见的I/O模型
Function:
Function:
Note:
Note:
*********************************************************************/
#pragma once
#ifndef __I_TCPSERV_SELECTMODEL
#define __T_TCPSERV_SELECTMODEL
/****************************头文件库*******************************/
#include "socket/UsrSocket.h"
#include<iostream>
using namespace std;
/****************************宏定义*********************************/
#define IPPORT 4000 // ip 端口
#define MAXBACKLOG SOMAXCONN // 客户最大连接数
/****************************函数实现*******************************/
#ifdef __cplusplus
extern "C" {
#endif
int g_itotalconn = 0; // 连接数量singre
SOCKET g_clientsocketarry[FD_SETSIZE] = {0}; //套接字数组
DWORD WINAPI WorkerThread(LPVOID lpParam); //线程
void CreateTcpServ_SelectModel()
{
CUsrSocket us_socket;
CUsrSocket::_STOCKET _socket_param;
_socket_param._af = AF_INET;
_socket_param._protocol = SOCK_STREAM;
_socket_param._type = 0;
CUsrSocket::_SOCKET_ADDR _socket_addrparam;
_socket_addrparam._b_addrany = true;
_socket_addrparam._i_port = IPPORT;
_socket_addrparam._str_ip = "";
DWORD dw_threadid;
// 初始化套接字
if(us_socket.InitWSAData(us_socket._wVersionRequested, us_socket._wsaData))
{
cout<<"InitWSAData successed!"<<endl;
}else{
cout<<"InitWSAData fauiled!"<<endl;
return;
}
// 创建套接字对象
us_socket._socket_no = us_socket.CreateSocket(_socket_param._af, _socket_param._protocol, _socket_param._type);
// 设置套接字地址
us_socket._socket_addr = us_socket.SetSocketAddr(_socket_addrparam._b_addrany ,
_socket_addrparam._str_ip, _socket_addrparam._i_port);
// bind
us_socket.SocketBind(us_socket._socket_no, us_socket._socket_addr);
// listen
us_socket.SocketListen(us_socket._socket_no, MAXBACKLOG);
// Create worker thread
//创建线程
CreateThread(NULL, 0, WorkerThread, NULL, 0, &dw_threadid);
while (1)
{
us_socket._socket_conn = us_socket.SocketAccept(us_socket._socket_no, us_socket._socket_client);
if (us_socket._socket_conn == INVALID_SOCKET)
continue;
else{
//这里client的SOCKADDR_IN client 中可以取出IP
cout<<"Accepted client:" <<inet_ntoa(us_socket._socket_client.sin_addr)<<ntohs(us_socket._socket_client.sin_port)<<endl;
// Add socket to g_clientsocketarry
//把客户端套接字放入数组中
g_clientsocketarry[g_itotalconn++] = us_socket._socket_conn;
//-send-
char sendBuf[DEFAULT_BUFLEN];
memset(sendBuf, 0 , DEFAULT_BUFLEN);
sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(us_socket._socket_client.sin_addr));//inet_ntoa网络地址转换转点分十进制的字符串指针
send(us_socket._socket_conn, sendBuf, strlen(sendBuf)+1,0);
}
}
return;
}
DWORD WINAPI WorkerThread(LPVOID lpParam)//线程
{
int i;
fd_set fdread;//结构
int ret;
struct timeval tv = { 1, 0 };//超时时间 SELECT模型中用到的这里是1秒
char szMessage[DEFAULT_BUFLEN];//信息数组,事实上就是个缓冲区
memset(szMessage, 0, DEFAULT_BUFLEN);
while (TRUE)
{
FD_ZERO(&fdread);//清空fd_set结构
for (i = 0; i < g_itotalconn; i++)
{
FD_SET(g_clientsocketarry[i], &fdread);//把客户套接字放到SELECT要求的数组中
}
//**************************************
// We only care read event
//只关心读的情况
ret = select(0, &fdread, NULL, NULL, &tv);
if (ret == 0)
{
// Time expired 超时
continue;
}
//如果SELECT返回不是0
for (i = 0; i < g_itotalconn; i++)
{
if (FD_ISSET(g_clientsocketarry[i], &fdread))
{
// A read event happened on g_clientsocketarry[i]
//一个可读发生在这个套接字上
// 每次接收消息之前都应该将缓存情况
memset(szMessage, 0 , DEFAULT_BUFLEN);
ret = recv(g_clientsocketarry[i], szMessage, DEFAULT_BUFLEN, 0);
cout<<"ClientNO: "<< g_clientsocketarry[i] <<szMessage<<endl;
//把它读出到缓冲区
if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() == WSAECONNRESET))
{
// Client socket closed
//客户端关闭
cout<<"Client socket closed NO: "<< g_clientsocketarry[i]<<endl;
closesocket(g_clientsocketarry[i]);//关闭这个套接字
if (i <= g_itotalconn - 1)
{
//将数组中最后一个套接字挪到当前的位置上 全部的client 删除 还会保留
// 刚好是数组最后一个 出现重复赋值,应该丢弃
if (i == g_itotalconn - 1)
{
g_clientsocketarry[--g_itotalconn] = 0;
}
else
{
g_clientsocketarry[i--] = g_clientsocketarry[--g_itotalconn];
}
}
cout<<g_itotalconn<<endl;
for (int j = 0; j < g_itotalconn; j++)
{
cout<<g_clientsocketarry[j]<<endl;
}
}
else
{
// We received a message from client
//如果以上没发生,那么就接收到一个客户端的信息
szMessage[ret] = '\0';
//直接回送回去
// send(g_clientsocketarry[i], szMessage, strlen(szMessage), 0);
cout<<"sendLength: "<<send(g_clientsocketarry[i], szMessage, strlen(szMessage), 0)<<endl;
}
}
}
}
return 0;
}
#ifdef __cplusplus
}
#endif
#endif