您的位置:首页 > 其它

简单的 winsock select模式

2016-04-03 19:22 405 查看
// WinSelectModel.cpp : 定义控制台应用程序的入口点。
//
//server side ,select model
/*
Syntax:
int select(
_In_    int                  nfds,//Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.
_Inout_ fd_set               *readfds,//An optional pointer to a set of sockets to be checked for readability.
_Inout_ fd_set               *writefds,//An optional pointer to a set of sockets to be checked for writability.
_Inout_ fd_set               *exceptfds,//An optional pointer to a set of sockets to be checked for errors.
_In_    const struct timeval *timeout//The maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.
)
功能:简单的讲就是一个socket“复用器”(不必为第个客户建立新线程,但需要不断轮询fd_set检测,fd_set的大小固定64),它能够检测报告一个或多个socket状态 ,但不如WSAASyncSelct()那么细致,第次调用,select ()把一组socket作为输入参数,而且它是阻塞的(可设置),也就是说该函数能使你同时检测多个socket的状态,它需要通过返回值来带回执行结果
Return value:成功返回当前状态与设定状态相匹配的socket的总数,超时返回0(timeout参数),失败返回SOCKET_ERROR
remarks:它与BSD兼容 ,也可以使用WSAAsyncSelect() ,timeout非零则阻塞,零则不阻塞(但不要传NULL为无限阻塞)
应用:网络连接数不大的程序
与select配合使用的宏
FD_ZERO(*set) :对fd_set初始化
FD_SET(s, *set):添加指定s套接字至集合
FD_CLR(s, *set):删除指定s套接字至集合
FD_ISSET(s, *set):检查指定s套接字是否集合
FD_SETSIZE: 64
*/
#include "stdafx.h"
#include<iostream>
#include<WinSock2.h>                    // socket 所需要的头文件
#pragma comment(lib,"WS2_32.lib")// link socket 库
#define PORT 6666
#define BUFLEN 1024
using namespace std;
fd_set g_fdClientSocket;
//fd_set
DWORD WINAPI ThreadProc(LPVOID lpParameter);
int main()
{

DWORD dwThreadID;
sockaddr_in addrClient;
int addrClientLen = sizeof(addrClient);
SOCKET sServer = INVALID_SOCKET;
SOCKET sClient;
int nClientCount = 0;
// 1 启动并初始化winsock(WSAStarup)
WSADATA wsaData;
if (WSAStartup(0x202, &wsaData))//成功返回0
{
return FALSE;
}
//2 创建套接字(socket)
sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sServer)
{
WSACleanup();
return FALSE;
}
//3 准备通信地址
SOCKADDR_IN addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(PORT);//服务器用于监听的端口号,客户端需要知道这个端口进行连接
addrServer.sin_addr.s_addr =  INADDR_ANY;
//4 绑定地址与socket(bind)
if (SOCKET_ERROR == bind(sServer, (const sockaddr*)&addrServer, sizeof(SOCKADDR_IN)))
{
closesocket(sServer);
WSACleanup();
return FALSE;
}
//5 监听 (listen)
if (SOCKET_ERROR == listen(sServer, SOMAXCONN))
{
closesocket(sServer);
WSACleanup();
}
//6 线程利用select()处理可读的客户端
CreateThread(NULL, 0, ThreadProc, NULL, 0, &dwThreadID);
// 7 等待多个客户端连接(accpet)
while (nClientCount<FD_SETSIZE)
{
sClient= accept(sServer, (sockaddr *)&addrClient, &addrClientLen);
if (INVALID_SOCKET == sClient)
{
cout << WSAGetLastError() << endl;
//或根据错误码进行其他操作
closesocket(sServer);
closesocket(sClient);
WSACleanup();
return FALSE;
}
printf("Accepted client:%s:%d\n", inet_ntoa(addrClient.sin_addr), ntohs(addrClient.sin_port));
FD_SET(sClient,& g_fdClientSocket);
nClientCount++;
}
system("pause");
return TRUE;
}
// 只处理是可读状态的socket
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
fd_set fdRead;
fd_set fdWrite;
FD_ZERO(&fdRead);
FD_ZERO(&fdWrite);

int nRet = 0;

char recvBuffer[1024] = {};

struct timeval stTimeOut = { 1,0 };

while (true)
{
fdRead = g_fdClientSocket;
fdWrite = g_fdClientSocket;
nRet = select(0, &fdRead, &fdWrite, NULL, &stTimeOut);
if (SOCKET_ERROR != nRet)
{
for (int i = 0; i < g_fdClientSocket.fd_count; i++)
{
if (FD_ISSET(g_fdClientSocket.fd_array[i], &fdRead))
{
memset(recvBuffer, 0, sizeof(recvBuffer));
SOCKADDR_IN stAddrTemp;
int nTempLen = sizeof(stAddrTemp);
nRet = recvfrom(g_fdClientSocket.fd_array[i], recvBuffer, sizeof(recvBuffer), 0, (sockaddr*)&stAddrTemp, &nTempLen);
if (SOCKET_ERROR == nRet)
{
closesocket(g_fdClientSocket.fd_array[i]);
FD_CLR(g_fdClientSocket.fd_array[i], &g_fdClientSocket);
}
else
{
cout << "the client(" << inet_ntoa(stAddrTemp.sin_addr) << ":" << ntohs(stAddrTemp.sin_port) << ") :" << recvBuffer << "(message size is " << nTempLen << ")" << endl;
}
}
if (FD_ISSET(g_fdClientSocket.fd_array[i], &fdWrite))
{
nRet = send(g_fdClientSocket.fd_array[i], "hello Client", sizeof("hello Client"), 0);
if (SOCKET_ERROR == nRet)
{
int nErrorNo = WSAGetLastError();
cout << "send error code is " << nErrorNo << endl;//10038  socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.
closesocket(g_fdClientSocket.fd_array[i]);
FD_CLR(g_fdClientSocket.fd_array[i], &g_fdClientSocket);
}
else
{
continue;
}
}
}
}
}
}


// WinSelectClient.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include<WinSock2.h>
//客户端
#include<iostream>
#pragma comment(lib,"WS2_32.lib")
using namespace std;
#define BUFLEN 1024
#define PORT 6666
void getIP(char*szHostaddress);
void SendProc();
SOCKET sHost;
int main()
{
WSADATA wsaData;
// 1 启动并初始化winsock(WSAStarup)
if (WSAStartup(MAKEWORD(2, 2), &wsaData))//成功返回0
{
return FALSE;
}
//2 创建套接字(socket)
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost)
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
//3 准备通信地址
char szHostaddress[200];
getIP(szHostaddress);
SOCKADDR_IN addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(PORT);
addrServer.sin_addr.s_addr = inet_addr(szHostaddress);
//4 连接服务器(connect)
if (SOCKET_ERROR == connect(sHost, (const sockaddr*)&addrServer, sizeof(addrServer)))//连接到指定的地址
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
//5 发送数据 (send)
char sendBuf[BUFLEN] = "你好服务器!";
if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0))
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
cout << "客户端发送消息成功!" << endl;
//7 接收数据(recv)
char recvBuf[BUFLEN];
ZeroMemory(recvBuf, sizeof(recvBuf));
if (SOCKET_ERROR == recv(sHost, recvBuf, sizeof(recvBuf), 0))
{
closesocket(sHost);
WSACleanup();
return FALSE;
}
cout << "服务器发来的消息:" << recvBuf << endl;
while (true)
{
SendProc();
Sleep(1000);
}
system("pause");
}
void SendProc(
)
{
char sendBuf[BUFLEN] = "你好服务器!";
if (SOCKET_ERROR == send(sHost, sendBuf, sizeof(sendBuf), 0))
{
closesocket(sHost);
WSACleanup();
return ;
}
cout << "客户端发送消息成功!" << endl;
}

void getIP(char*szHostaddress) {
char szHostname[100];
if (gethostname(szHostname, sizeof(szHostname)) != SOCKET_ERROR)//先得到主机名
{
HOSTENT *pHostEnt = gethostbyname(szHostname);//通过名字拿到地址
if (pHostEnt != NULL)
{
sprintf(szHostaddress, "%d.%d.%d.%d",
(pHostEnt->h_addr_list[0][0] & 0x00ff),
(pHostEnt->h_addr_list[0][1] & 0x00ff),
(pHostEnt->h_addr_list[0][2] & 0x00ff),
(pHostEnt->h_addr_list[0][3] & 0x00ff));
}
}
else
return;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: