分享
 
 
 

windows网络编程之Winsock(三)非阻塞select模式服务器

王朝system·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

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

//

/************************************

作者: wangweixing2000

Revision By: 0.01

Revised on 2005-6-29 11:52:03

Comments: SelectModeWinSock 该程序中存在bug,没有处理多线程数据访问的冲突和判断客户端断开的有效处理!哪位有兴趣可以加上!

************************************/

//select(选择)模型,是利用select函数实现对i/o的管理。select函数可以用于

//判断套接字上是否存在数据,或者能否向一个套接字写入数据。

/*

int select(

int nfds, //被忽略参数,为了保持和早期Berkeley套接字应用程序兼容而保留的这个参数

fd_set* readfds, //检查可读性fd_set*参数

fd_set* writefds, //检查可写性fd_set*参数

fd_set* exceptfds, //带外数据

const struct timeval* timeout //指定select等待i/o操作完成时,最多等待多长时间。

);

typedef struct timeval

{

long tv_sec; //以秒为单位指定等待的时间

long tv_usec; //以毫秒为单位指定的等待时间

} timeval;

用select对套接字进行监听前,应用程序必须将套接字句柄分配给一个集合,设置好一个或所有的读、写以及例外的

fd_set结构。将一个套接字分配给任何一个集合后,再来调用select,便可知道某个套接字上是否正在发生i/o活动。

Winsock提供了几个宏用来处理fd_set:

FD_ZERO(*set) //清空fd_set*

FD_CLR(s,*set) //从set中删除s套接字

FD_ISSET(s,*set) //检查s是否是set集合的一名成员,如果是返回TRUE

FD_SET(s,*set) //设置套接字s加入集合set中

*/

#include "stdafx.h"

#include <iostream>

#include <Winsock2.h>

#include <ws2tcpip.h>

#pragma comment(lib,"WS2_32.lib")

using namespace std;

struct SocketObj

{

SOCKET socket; //当前对象的socket

BOOL listening; //该套接字是否已经

SocketObj *next, //向后

*prev; //向前

};

SocketObj *g_pSocketList = NULL; //Socket连表

SocketObj *g_pSocketEnd = NULL; //连表的尾部

int g_nSocketCount = 0;

HANDLE g_hSelect;

//创建SocketObj

SocketObj* GetSocketObj(SOCKET s,BOOL listening)

{

SocketObj *newSocketObj = NULL;

newSocketObj = (SocketObj*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SocketObj));

if(newSocketObj == NULL)

{

cout<<"GetSocketObj: HeapAlloc failed: "<< GetLastError()<<endl;

ExitProcess(-1); //结束进程

}

newSocketObj->socket = s;

newSocketObj->listening = listening;

return newSocketObj;

}

//插入一个SocketObj

void InserSocketObj(SocketObj *obj)

{

obj->next = obj->prev = NULL;

if(g_pSocketList == NULL)

{

g_pSocketList = g_pSocketEnd = obj;

}

else

{

obj->prev = g_pSocketEnd;

g_pSocketEnd->next = obj;

g_pSocketEnd = obj;

}

g_nSocketCount++;

}

//删除

void RemoveSocketObj(SocketObj *obj)

{

if(obj->prev)

{

obj->prev->next = obj->next;

}

if(obj->next)

{

obj->next->prev = obj->prev;

}

if(obj == g_pSocketList)

{

g_pSocketList = obj->next;

}

if(obj == g_pSocketEnd)

{

g_pSocketEnd = obj->prev;

}

g_nSocketCount--;

HeapFree(GetProcessHeap(),0,obj);

}

//监听线程

DWORD WINAPI ListenThread(void *pVoid)

{

cout<<"server start listening!"<<endl;

SOCKADDR_IN ClientAddr; // 定义一个客户端得地址结构作为参数

int addr_length=sizeof(ClientAddr);

SOCKET *listen = (SOCKET*)pVoid;

SocketObj *pSocketObj = NULL;

while(1)

{

SOCKET Client = accept(*listen,(sockaddr*)&ClientAddr,&addr_length);

if(Client == INVALID_SOCKET)

{

cout<<"accept failed!"<<endl;

continue;

}

// 这里可以取得客户端的IP和端口,但是我们只取其中的SOCKET编号

LPCTSTR lpIP = inet_ntoa(ClientAddr.sin_addr);

UINT nPort = ClientAddr.sin_port;

cout<<"一个客户端已经连接!IP:"<<lpIP<<"SOCKET 端口号:"<<nPort<<endl;

//创建SocketObj并添加如list

pSocketObj = GetSocketObj(Client,TRUE);

InserSocketObj(pSocketObj);

if(g_nSocketCount == 1) //如果有一个客户端就唤起select线程

{

ResumeThread((HANDLE)g_hSelect);

}

}

return 0;

}

//select线程函数

DWORD WINAPI SelectThread(void *pVoid)

{

SocketObj *sptr = NULL;

fd_set readfds,

writefds,

exceptfds;

timeval timeout;

char Buffer[4096];

while(TRUE)

{

//清空fd_set

FD_ZERO(&readfds);

FD_ZERO(&writefds);

FD_ZERO(&exceptfds);

//设置timeout

timeout.tv_sec = 5;

timeout.tv_usec = 0;

sptr = g_pSocketList;

//设置fd_set

while(sptr)

{

FD_SET(sptr->socket,&readfds);

FD_SET(sptr->socket,&writefds);

FD_SET(sptr->socket,&exceptfds);

sptr = sptr->next;

}

//开始select

int ret = select(0,&readfds,&writefds,NULL,&timeout);

if(ret == SOCKET_ERROR)

{

cout<<"select failed!"<<endl;

WSACleanup();

return -1;

}

else if(ret == 0)

{

//超时

cout<<"time out!"<<endl;

continue;

}

else

{

sptr = g_pSocketList;

while(sptr)

{

if(FD_ISSET(sptr->socket,&readfds))

{

ZeroMemory(Buffer,4096);

int re = recv(sptr->socket,Buffer,4096,0);

if(re == SOCKET_ERROR)

{

return -1;

}

else if(re == 0)

{

//该客户端已经断开

closesocket(sptr->socket);

SocketObj *tmp = sptr;

sptr = sptr->next;

RemoveSocketObj(tmp);

continue;

}

else

{

cout<<"recv buffer:"<<Buffer<<endl;

}

}

if(FD_ISSET(sptr->socket,&writefds))

{

//发送数据给当前客户端

char *sendBuffer = "wwx send msg!";

int re = send(sptr->socket,sendBuffer,16,0);

if(re == SOCKET_ERROR)

{

return -1;

}

else if(re == 0)

{

continue;

}

else

{

//这里可以显示发送是否成功

//cout<<"send successed!"<<endl;

}

}

sptr = sptr->next;

}

}

}

return 0;

}

int _tmain(int argc, _TCHAR* argv[])

{

WSAData wsaData;

SOCKET Listen;

SocketObj *pSockobj = NULL;

SOCKET Accept = INVALID_SOCKET;

SOCKADDR_IN ServerAddr;

//初始化Winsock库

int ret = WSAStartup(MAKEWORD(2,2),&wsaData);

if(ret != 0)

{

cout<<"WSAStartup error!"<<endl;

WSACleanup();

return -1;

}

Listen = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if(Listen == INVALID_SOCKET)

{

cout<<"Listen create failed!"<<endl;

WSACleanup();

return -1;

}

//绑定

ServerAddr.sin_family = AF_INET;

ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

ServerAddr.sin_port = htons(10012);

ret = bind(Listen,(sockaddr*)&ServerAddr,sizeof(SOCKADDR_IN));

if(ret == SOCKET_ERROR)

{

cout<<"bind failed!"<<endl;

closesocket(Listen);

WSACleanup();

return -1;

}

//监听

listen(Listen,200);

//开启监听线程

HANDLE hListen = CreateThread(NULL,0,ListenThread,&Listen,0,NULL);

if(hListen == NULL)

{

cout<<"Create ListenThread failed!"<<endl;

}

//创价挂起的select线程,因为刚开始没有连接的客户端

g_hSelect = CreateThread(NULL,0,SelectThread,NULL,CREATE_SUSPENDED,NULL);

if(g_hSelect == NULL)

{

cout<<"Create SelectThread failed!"<<endl;

}

system("PAUSE");

return 0;

}

如果引用该文,请注明出处!谢谢!

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有