怎样把select()模型改成异步模式的

wuxia2118 2018-12-31 09:44:09
由于使用select()模型可以实现TCP的一对多通信,所以我想使用select()模型制作一个群聊软件,服务器端可以接收所有客户端发来的消息,并将接收的消息显示到列表框中。可问题是select()模型没法自动接收消息,因为select()模型是非阻塞的但并不是异步的。
我从书上看了一个控制台界面的服务器端程序,由于控制台程序接收到消息后会自动弹出,所以不存在上面的问题,可我想把它改成MFC版的程序,就出现了上面的问题,要怎么样让任意客户端发来消息后,服务器端都会自动显示消息在列表框中呢。下面是我的程序,要怎么修改好啊。

void CSelwinsDlg::OnCreate() 
{
/***初始化winsock2.DLL***/
WSADATA wsaData;
WORD wVersionRequested=MAKEWORD(2,2); //生成版本号2.2
if(WSAStartup(wVersionRequested,&wsaData)!=0)
{
c_recvbuf.AddString("加载winsock.dll失败!\n");

}
/***创建套接字***/
if ((sock_server = socket(AF_INET,SOCK_STREAM,0))<0)
{
c_recvbuf.AddString("创建套接字失败!\n");
WSACleanup();

}
/***填写要绑定的本地地址***/
int addr_len = sizeof(struct sockaddr_in);
memset((void *)&addr,0,addr_len);
addr.sin_family =AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);//允许套接字使用本机的任何IP
/***给监听套接字绑定地址***/
if(bind(sock_server,( struct sockaddr *)&addr,sizeof(addr))!=0)
{
c_recvbuf.AddString("地址绑定失败!\n");
closesocket(sock_server);
WSACleanup();

}
/***将套接字设为监听状态****/
if(listen(sock_server,0)!=0)
{
c_recvbuf.AddString("listen函数调用失败!\n");
closesocket(sock_server);
WSACleanup();

}
else
c_recvbuf.AddString("listenning......\n");
FD_ZERO(&fdsock);//初始化fdsock
FD_SET(sock_server, &fdsock);//将监听套接字加入到套接字集合fdsock
/***循环:接收连接请求并收发数据***/
while(true)
{
FD_ZERO(&fdread);//初始化fdread
fdread=fdsock;//将fdsock中的所有套接字添加到fdread中
if(select(0, &fdread, NULL, NULL, NULL)>0)
{
for(int i=0;i<fdsock.fd_count;i++)
{
if (FD_ISSET(fdsock.fd_array[i], &fdread))
{
if(fdsock.fd_array[i]==sock_server)
{ //有客户连接请求到达,接收连接请求
newsock=accept (sock_server, (struct sockaddr *) &client_addr, &addr_len);
if(newsock==INVALID_SOCKET)
{ //accept出错终止所有通信,结束程序
c_recvbuf.AddString("accept函数调用失败!\n");
for(int j=0;j<fdsock.fd_count;j++)
closesocket(fdsock.fd_array[j]); //关闭所有套接字
WSACleanup();//注销WinSock动态链接库

}
else
{
c_recvbuf.AddString(inet_ntoa(client_addr.sin_addr));
send(newsock,msg,sizeof(msg),0) ;//发送一段信息
FD_SET(newsock, &fdsock);//将新套接字加入fdsock
}
}
else
{ //有客户发来数据,接收数据
memset((void *) msgbuffer,0, sizeof(msgbuffer));//缓冲区清零
int size=recv(fdsock.fd_array[i],msgbuffer,sizeof(msgbuffer),0);
if(size<0) //接收信息
c_recvbuf.AddString("接收信息失败!");
else if(size==0)
c_recvbuf.AddString("对方已关闭!\n");
else
{ //显示收到信息
getpeername(fdsock.fd_array[i], (struct sockaddr *)&client_addr, &addr_len); //获取对方IP地址
c_recvbuf.AddString( msgbuffer );
}
closesocket(fdsock.fd_array[i]); //关闭套接字
FD_CLR(fdsock.fd_array[i],&fdsock);//清除已关闭套接字
}
}
}
}
else
{
c_recvbuf.AddString("Select调用失败!");
break;//终止循环退出程序
}
}
}
...全文
388 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
wuxia2118 2019-01-11
  • 打赏
  • 举报
回复
基本懂了,Select模型如果要编写Windows界面程序必须使用多线程,否则就会把程序界面线程堵塞。Select是非阻塞模型,非阻塞并不一定是异步模型,但异步模型一定是非阻塞的。
xiaohuh421 2019-01-09
  • 打赏
  • 举报
回复
你这个说法都是错误的. "select()模型是非阻塞的但并不是异步" 非阻塞, 就是为了实现异步的. 只你跟你要求的异步不同, 你需要recv收到消息后, 把消息内容POST到主线程, 再添加到消息框中. 解决办法有几种: 1. recv后, 直接把消息内容通过PostMessage发送的UI线程(你的主窗口), 然后把消息内容解析出来, 添加到消息框中. 2. recv后, 添加到一个消息队列中. 另启动一个线程,专门负责从消息队列中取出消息, 然后添加到消息框中
wuxia2118 2019-01-02
  • 打赏
  • 举报
回复
OnCreate是一个按钮事件,有个ID是IDC_Create的按钮。
红牛工作室 2019-01-02
  • 打赏
  • 举报
回复
你OnCreate在主线程里调用.UI被阻塞了所以接收不到,只能再开一个线程
红牛工作室 2019-01-02
  • 打赏
  • 举报
回复
你OnCreate在主线程里调用.UI补
zgl7903 2019-01-01
  • 打赏
  • 举报
回复
smwhotjay 2019-01-01
  • 打赏
  • 举报
回复
开启线程,专门select recv消息。
你这个OnCreate 完全是阻塞的,while死循环啊。当然开线程,调用OnCreate 是可以的。那样就不卡主界面 了
wuxia2118 2019-01-01
  • 打赏
  • 举报
回复
引用 1 楼 smwhotjay 的回复:
开启线程,专门select recv消息。
你这个OnCreate 完全是阻塞的,while死循环啊。当然开线程,调用OnCreate 是可以的。那样就不卡主界面 了


不是说Select模型可以实现一对多通信吗,难道单线程就无法实现我上面的程序吗。
我又试了一下,上面的程序能够接收到客户端的消息,但是只能接收到客户端发的第一条消息,然后客户端就显示“正常关闭连接”,应该是服务器端的Select模型触发了客户端的FD_CLOSE事件,我在网上看说Select模型会发送0字节的心跳数据包给客户端,难道是这个原因吗。

而且服务器端启动后,一直处于阻塞状态,我在服务器端加ioctlsocket(newsock,FIONBIO,&nonBlock);仍然也是阻塞状态。

而且上面的程序只能用AfxMessageBox( msgbuffer);接收消息,却不能用c_recvbuf.AddString( msgbuffer );将消息添加到列表框中,不知道为啥。
Nginx for Windows v1 5 9 Nginx是一款轻量级的Web服务器 反向代理服务器及电子邮件IMAP POP3)代理服务器 并在一个BSD like 协议下发行 Nginx由俄罗斯的程序设计师Igor Sysoev所开发 可供大型的门户网站及搜索引擎使用 Nginx是一个很强大的高性能Web和反向代理服务器 它具有很多非常优越的特性 Nginx可以在大多数 Unix like OS 上编译运行 在Linux和unix上分别采用epoll和kqueue网络模型 能够支持高达 50 000 个并发连接数的响应(实际上可能更大) Nginx支持与客户端建立SSL安全连接 因此可以作为SSL安全网关使用 Nginx有Windows移植版 在Windows平台上支持select和iocp两种网络IO模型 在Windows平台上 Nginx的表现可能没有在其它平台上那么优秀 从目前的版本看 Nginx主要有以下几点可能需要改进的地方: 1 Nginx采用多进程并行处理的运行方式 不支持多线程(似乎各平台下都不支持多线程) 2 在Windows下 只支持select和iocp两种网络IO模型 其中iocp模型虽然可以支持高并发连接 但目前版本的iocp只支持Web服务器(有的版本使用iocp作WEB服务器都跑不通) 不支持反向代理服务器 更不支持SSL连接;而select模型不能支持高并发连接 如果要实现高并发 必须使用非常多的进程 3 由于Windows vista之后版本的共享内存在不同进程中的地址不同 因此 在启用多进程时 不能使用共享内存来做SSL的session缓存 也就是说 要实现SSL 只能使用单进程 从而限制了并发连接数 (造成这种结果的原因 可能是作者对Nginx在Windows平台下的应用不太重视 在共享内存中使用了绝对地址指针 如果改成相对地址偏移则可避免) 笔者试图突破上面的限制 在 Nginx v1 5 9 的基础上作了三点改进: 1 完善iocp模型 使其能够支持代理服务器 2 增加wsa网络IO模型(Windows socket异步IO模型) 该模型支持WEB服务器 反向代理服务器和SSL安全连接 与Linux下的epoll具有同等的功能和效率 3 增加Windows和Linux平台下的多线程支持(Unix下尚未实现) 多线程可支持select epoll wsa和iocp网络IO模型 并支持SSL连接 通过上述改进 Nginx在Windows平台下的性能得到大幅提高 其并发连接数一般情况下可达到10万以上 最多可达到40万个 如何使用wsa网络IO模型 与使用iocp模型类似 在配置文件中 增加配置项: use wsa; 如何使用多线程 在配置文件中 增加配置项: worker threads 50; 线程数最大128 笔者邮箱: xiong rh@sina com">Nginx for Windows v1 5 9 Nginx是一款轻量级的Web服务器 反向代理服务器及电子邮件IMAP POP3)代理服务器 并在一个BSD like 协议下发行 Nginx由俄罗斯的程序设计师Igor Sysoev所开发 可供大型的门户网站及搜索引擎使用 Nginx [更多]
Nginx for Windows v1 5 9 source code Nginx是一款轻量级的Web服务器 反向代理服务器及电子邮件IMAP POP3)代理服务器 并在一个BSD like 协议下发行 Nginx由俄罗斯的程序设计师Igor Sysoev所开发 可供大型的门户网站及搜索引擎使用 Nginx是一个很强大的高性能Web和反向代理服务器 它具有很多非常优越的特性 Nginx可以在大多数 Unix like OS 上编译运行 在Linux和unix上分别采用epoll和kqueue网络模型 能够支持高达 50 000 个并发连接数的响应(实际上可能更大) Nginx支持与客户端建立SSL安全连接 因此可以作为SSL安全网关使用 Nginx有Windows移植版 在Windows平台上支持select和iocp两种网络IO模型 在Windows平台上 Nginx的表现可能没有在其它平台上那么优秀 从目前的版本看 Nginx主要有以下几点可能需要改进的地方: 1 Nginx采用多进程并行处理的运行方式 不支持多线程(似乎各平台下都不支持多线程) 2 在Windows下 只支持select和iocp两种网络IO模型 其中iocp模型虽然可以支持高并发连接 但目前版本的iocp只支持Web服务器(有的版本使用iocp作WEB服务器都跑不通) 不支持反向代理服务器 更不支持SSL连接;而select模型不能支持高并发连接 如果要实现高并发 必须使用非常多的进程 3 由于Windows vista之后版本的共享内存在不同进程中的地址不同 因此 在启用多进程时 不能使用共享内存来做SSL的session缓存 也就是说 要实现SSL 只能使用单进程 从而限制了并发连接数 (造成这种结果的原因 可能是作者对Nginx在Windows平台下的应用不太重视 在共享内存中使用了绝对地址指针 如果改成相对地址偏移则可避免) 笔者试图突破上面的限制 在 Nginx v1 5 9 的基础上作了三点改进: 1 完善iocp模型 使其能够支持代理服务器 2 增加wsa网络IO模型(Windows socket异步IO模型) 该模型支持WEB服务器 反向代理服务器和SSL安全连接 与Linux下的epoll具有同等的功能和效率 3 增加Windows和Linux平台下的多线程支持(Unix下尚未实现) 多线程可支持select epoll wsa和iocp网络IO模型 并支持SSL连接 通过上述改进 Nginx在Windows平台下的性能得到大幅提高 其并发连接数一般情况下可达到10万以上 最多可达到40万个 如何使用wsa网络IO模型 与使用iocp模型类似 在配置文件中 增加配置项: use wsa; 如何使用多线程 在配置文件中 增加配置项: worker threads 50; 线程数最大128 nginx v1 5 9 win src在vs2008环境下开发 笔者邮箱: xiong rh@sina com">Nginx for Windows v1 5 9 source code Nginx是一款轻量级的Web服务器 反向代理服务器及电子邮件IMAP POP3)代理服务器 并在一个BSD like 协议下发行 Nginx由俄罗斯的程序设计师Igor Sysoev所开发 可供大型的门户网站及搜索引擎使用 [更多]

18,355

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧