Windows网络编程--选择(select)模型

选择模型是I/O模型中最简单的一个。Server端通过创建两个套接字集合fdOld和fdNew,在循环中通过事件添加和移除未决IO套接字句柄。测试的时候先启动服务端再启动客户端。

以下为Server端源代码(在VS2010下测试通过):

#include "stdafx.h"
#include<WinSock2.h>
#include<Windows.h>

#include<iostream>

#pragma comment(lib,"ws2_32.lib")
using namespace std;

BOOL InitSocket();
BOOL SelectMode();

int _tmain(int argc, _TCHAR* argv[])
{
if(InitSocket()==FALSE)
{
return 0;
}
if(SelectMode()==FALSE)
{

}
WSACleanup;
return 0;
}
BOOL InitSocket()
{
WSAData wsaData={0};
if(WSAStartup(MAKEWORD(2,2),&wsaData)==0)
{
return TRUE;
}
return FALSE;
}
BOOL SelectMode()
{
//创建监听套接字
SOCKET sListenSocket;
sListenSocket=socket(AF_INET,SOCK_STREAM,0);
if(sListenSocket==INVALID_SOCKET)
{
return FALSE;
}
sockaddr_in ServerAddr;
ServerAddr.sin_family=AF_INET;
ServerAddr.sin_port=htons(2356);
ServerAddr.sin_addr.S_un.S_addr=INADDR_ANY;
int iResult=bind(sListenSocket,(SOCKADDR*)&ServerAddr,sizeof(ServerAddr));
if(iResult==SOCKET_ERROR)
{
return FALSE;
}
listen(sListenSocket,5);

//创建套接字集合
fd_set fdOld;
fd_set fdNew;
//初始化套接字集合
fdOld.fd_count=0;
fdNew.fd_count=0;
//将监听套接字放到fdOld集合当中
FD_SET(sListenSocket,&fdOld);

while(true)
{
//将fdOld集合的一个拷贝fdNew传递给Select函数
//当有事件发生时,select函数移除fdNew集合中没有未决I/O操作的套接字句柄,然后返回
fdNew=fdOld;
int iReturn=select(0,&fdNew,NULL,NULL,NULL);//第一个参数忽略,第二个参数指向一个套接字集合,检查其可读性,第三个参数指向一个套接字集合,检查其可写性
//第四个参数指向一个套接字集合,检查错误,第五个参数指定此函数等待的最长时间,如果为NULL,则为无限长
int i=0;
for(i=0;i<fdOld.fd_count;i++)
{
if(FD_ISSET(fdOld.fd_array[i],&fdNew)!=0)//确定哪些套接字有未决I/O
{
if(fdOld.fd_array[i]==sListenSocket)//如果该套接字为监听套接字
{
//定义一个通信套接字
SOCKET sClientSocket;
sockaddr_in Clientaddr;
int addrlen=sizeof(Clientaddr);
sClientSocket=accept(sListenSocket,(SOCKADDR*)&ServerAddr,&addrlen);
if(sClientSocket==INVALID_SOCKET)
{
continue;
}
//将通信套接字放入fdOld中
if(fdOld.fd_count<FD_SETSIZE)
{
FD_SET(sClientSocket,&fdOld);
}
else
{
send(sClientSocket,"Waiting",strlen("Waiting"),0);
closesocket(sClientSocket);
}
continue;
}
else//如果该套接字为通信套接字
{
char szBuffer[0x1000]={0};
int iLength=recv(fdOld.fd_array[i],szBuffer,0x1000,0);
if(iLength<0)//返回值小于零说明客户端关闭了,则关闭fdOld集中中相应的通信套接字
{
closesocket(fdOld.fd_array[i]);
FD_CLR(fdOld.fd_array[i],&fdOld);
cout<<"One Client Lost"<<endl;
continue;
}
szBuffer[iLength]=‘\0‘;
cout<<szBuffer<<endl;
}
}
}

}
}

以下为Client源代码:

#include "stdafx.h"
#include <WinSock2.h> //这个头文件必须放前面,在Ws2_32.dll里
#include <Windows.h> //在kernel32.dll里
#include <iostream>
#pragma comment(lib,"Ws2_32.lib") //加载静态库
using namespace std;
SOCKET sClientSocket;
bool InitSocket();//启动套接字库
DWORD WINAPI RecvThread();//声明句柄

int _tmain(int argc, _TCHAR* argv[])
{
cout<<"Client"<<endl;
if(InitSocket()==false)//初始化失败
{
cout<<"Init Socket Error"<<endl;
return 0;
}
//通信套接字
sClientSocket = socket(AF_INET,SOCK_STREAM,0);

if (sClientSocket==INVALID_SOCKET)
{
cout<<"Create Listen Socket Error\r\n";

WSACleanup();

return 0;
}
//初始化网卡
SOCKADDR_IN ServerAddr;
ServerAddr.sin_family=AF_INET;//指示协议家族
ServerAddr.sin_addr.S_un .S_addr=inet_addr("192.168.1.113");//指示IP,inet_addr将IP地址转化为计算机能理解的形式
ServerAddr.sin_port=htons(2356); //端口,指示数据包在应用层相应端口来接受,就是发送数据和接受数据要用相同的端口,如果不是在广域网上,可以自己指示

//连接
int iRet=connect(sClientSocket,(sockaddr*)&ServerAddr,sizeof(ServerAddr));
if(iRet==SOCKET_ERROR)
{
cout<<"fail to connect";
}
HANDLE hThread =CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)RecvThread,NULL,0,NULL);//启动句柄
if(iRet==SOCKET_ERROR)//如果绑定失败,释放内存
{
cout<<"Connect Error"<<endl;
closesocket(sClientSocket);
WSACleanup();
return 0;
}

//接收数据
char szBuffer[0x1000]={0};
while(true)//死循环,让通信套接字持续工作
{

cin>>szBuffer;
send(sClientSocket,szBuffer,strlen(szBuffer),0);//发送数据
}
WaitForSingleObject(hThread,INFINITE);
WSACleanup();//解除与Socket库的绑定并且释放Socket库占用的资源
return 0;
}
DWORD WINAPI RecvThread()
{
while(true)
{
char szBuffer[0x1000]={0};
DWORD dwReturn=recv(sClientSocket,szBuffer,0x1000,0);//接收数据
if(dwReturn<=0)
{

break;
}

szBuffer[dwReturn]=‘\0‘;//记得加上\0
cout<<szBuffer<<endl;
}
return 0;
}

bool InitSocket()
{

WORD v1 = 0;
v1 = MAKEWORD(2,2);//指示Winsock2.2版本
WSADATA wsaData = {0};
if ((WSAStartup(v1,&wsaData)==0))//初始化Winsock Dll
{
return TRUE;
}

return FALSE;

}

时间: 2024-11-04 13:21:08

Windows网络编程--选择(select)模型的相关文章

0729------Linux网络编程----------使用 select 、poll 和 epoll 模型 编写客户端程序

1.select 模型 1.1 select 函数原型如下,其中 nfds 表示的描述符的最大值加1(因为这里是左闭右开区间),中间三个参数分别表示要监听的不同类型描述符的集合,timeout用来表示轮询的时间间隔,这里用NULL表示无限等待. 1.2 使用 select函数编写客户端程序的一般步骤: a)初始化参数,包括初始化监听集合read_set并添加fd,以及初始化监听的最大描述符 maxfd 和select的返回值 nready: b)将read_set 赋值给 ready_set,因

一.Windows I/O模型之选择(select)模型

1.选择(select)模型:选择模型:通过一个fd_set集合管理套接字,在满足套接字需求后,通知套接字.让套接字进行工作.避免套接字进入阻塞模式,进行无谓的等待.选择模型的核心的FD_SET集合和select函数.通过该函数,我们可以们判断套接字上是否存在数据,或者能否向一个套接字写入数据. 2.select函数:int select(    int nfds,//忽略,只是为了兼容而存在.    fd_set FAR* readfds,//可读性检查(有数据可读入,连接关闭,重设,终止) 

Windows网络编程

第一章 序言 我写这个专题的目的,一方面是为了通过对网络编程再一次系统的总结,提高自己的网络编程水平,特别是Windows下的网络编程水平.同一时候,我也希望,能为众多初学网络编程的人提供一点帮助,由于我開始学习网络编程的时候,能找到的资料就非常少.当然,花钱能够买到翻译版本号的书:) 首先向大家推荐一本非常好的參考书,Network Programming for Microsoft Windows 2nd, 初学网络编程的时候我还不知道有这样一本好书,仅仅是上各大论坛把能找到的网络编程方面的

Windows网络编程 2 【转】

Windows网络编程使用winsock.Winsock是一个基于Socket模型的API,在Windows系统中广泛使用.使用Winsock进行网络编程需要包含头文件Winsock2.h,需要使用库ws2_32.lib,包含方法:可以使用语句来告诉编译器连接该库#pragma comment(lib, “ws2_32.lib”);如果使用VS,可以通过“项目” --> “XX属性”--> “连接器”-->“输入”--> “附加依赖项”添加ws2_32.lib. (XX为当前工程名

Windows网络编程经验小结

转自:CSDN网友的强贴,其ID:gdy119 (夜风微凉) 1. 如果在已经处于 ESTABLISHED状态下的socket(一般由端口号和标志符区分)调用closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket: BOOL bReuseaddr=TRUE; setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char*)&bReuseaddr,sizeof(BOOL)); 2. 如果要已经处于连接状态的soket

Windows 网络编程(2)--重叠I/0模型

5).重叠I/O模式(overlapped) 常用函素: 1.WSASocket : 创建套接字 2.TCP WSASend WSARecv 3.UDP: WSASendTo WSARecvFrom 4.AccepEx (Mswsock.lib库导出) WSAIoctl 5.数据类型 WSAOVERLAPPED (wsaoverlapped) 函数: WSAGetOverlappedResult 使用: 缓冲区对象 typedef struct _BUFFER_OBJ { OVERLAPPED

Unix 网络编程 I/O 模型 第六章

前提,也是重点是, 当接收收据.或者读取数据时,分两步 1 等待数据准备好. 2 从内核拷贝数据到进程. 对于一个network IO 即 socket(这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel).当一个read操作发生时,它会经历两个阶段: 1 等待数据准备 (Waiting for the data to be ready) 2 将数据从内核拷贝到进程中 (Copying the data

72&gt;&gt;Windows 网络编程

1 网络编程 API 2 3 4 int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); lpWSAData 是一个返回值:成功返回 0,失败返回 -1,错误代码 WSASYSNOTREADY 表示基础网络子系统没有准备好网络通行,WSAVERNOTSUPPORTED 表示 Socket 版本不支持,WSAEINPROGRESS 表示一个阻塞的 Sockets 操作在进程中,WSAEPROCLIM 表示 Sockets 支持的

socket编程的select模型

在掌握了socket相关的一些函数后,套接字编程还是比较简单的,日常工作中碰到很多的问题就是客户端/服务器模型中,如何让服务端在同一时间高效的处理多个客户端的连接,我们的处理办法可能会是在服务端不停的监听客户端的请求,有新的请求到达时,开辟一个新的线程去和该客户端进行后续处理,但是这样针对每一个客户端都需要去开辟一个新的线程,效率必定底下. 其实,socket编程提供了很多的模型来处理这种情形,我们只要按照模型去实现我们的代码就可以解决这个问题.主要有select模型和重叠I/o模型,以及完成端