java异步处理机制选择机制是否对窗口界面处理部分造成困难

网络软件设计-socket编程
内容摘要:本文首先介绍了同步选择机制和异步选择机制的基本概念,然后通过讲述消息驱动与服务机制的矛盾引入了异步选择机制,接着本文结合一个实际的异步选择通信案例来具体介绍异步选择机制设计中的相关细节和方法,最后对异步选择机制的特点进行总结并和同步选择机制做了一番比较,得出结论。
关键字:异步选择&同步选择&服务&
Abstract:In&this&essay,&the&Synchronized&Selection&mechanism&and&Asynchronized&Selection&mechanism&is&introduced&at&first.&Then&it&tells&why&Asynchronized&Selection&mechanism&is&needed&via&the&conflict&between&event-driven&system&and&socket&service&mechanism.&After&that&a&practical&instance&for&Asynchronized&Selection&mechanism&is&given&to&explain&it&more&clearly&concerned&with&corresponding&design&methods&and&details.&At&last&a&conclusion&for&the&feature&of&Asynchronized&Selection&mechanism&and&the&difference&between&Synchronized&Selection&mechanism&and&it&is&shown.
Key&Words:
一、同步选择机制与异步选择机制的基本概念
1.同步选择机制简介
同步选择机制的应用是基于多路复用的实际问题模型。为了能够使多条连接上的数据同时通信,同步选择机制应运而生。
Select()函数是同步选择机制中最基础最核心的概念,下面对此函数的功能、参数和相关要素做必要的说明:
功能——该函数能检查多个套接字的状态,服务器可以根据这些信息做出相应的处理;
输入——套接字队列;
输出——各待查套接字的当前状态;
函数定义:
&&&&int&select&(&IN&int&nfds,&IN&OUT&fd_set&*&readfds,
&&&&&&&&&&&&&IN&OUT&fd_set&*writefds,&IN&OUT&fd_set&*exceptfds,
&&&&&&&&&&&&&IN&struct&timeval&*timeout&)
基于的程序可以认为是具有事件驱动的特点,而可以看做事件发生器,对事件进行分发处理。
Select同步选择机制处理事件的基本流程如下图所示:
图同步选择机制的事件处理流程
2.异步选择机制简介
异步选择机制的提出是为了解决窗口程序中所遇到的窗口无响应问题,这一点将在第二部分进行详细的说明。
因为异步选择机制是对同步选择机制的一些修正和改良,所以它不仅能够解决窗口不响应的问题,并且同样能顾实现多路复用。
异步选择机制中最核心的概念是WSAAsyncSelect()函数这一函数的详细说明也将在第二部分展开。
异步选择机制处理事件的基本流程如下图所示:
图异步选择机制的事件处理流程
二、选用异步选择机制的背景
1.消息驱动与服务机制的矛盾
下图是基于的消息驱动机制基本框架,可以看到,该框架中有两个循环:一个是基于(窗口)消息的循环,一个是基于(读事件、写事件等)的循环。
图基于的消息驱动机制
一个显而易见的事实是:当程序陷入基于的事件循环后,没有办法跳出,则不能正常响应窗口消息。
矛盾的根源在于:循环等待客户连接和循环等待客户数据。在窗口程序中循环或者阻塞都会影响到主线程对消息的响应。
2.解决矛盾的两种思路
根据上面提出的矛盾,有两种解决问题的思路:第一种办法是为所有需要循环等待的程序段生成线程,第二种办法是不在程序中循环等待并不断接受客户连接。
第一种办法的解决思想是:为需要循环等待客户连接的部分生成子线程,为需要循环等待数据连接的部分生成子线程。则程序框架如下所示:
图多线程解决方案
&第二种办法的解决思想如下图所示:
图异步响应解决方案
窗口程序是基于消息的,如果将客户连接、客户数据到达也映射为消息则通信程序也可以基于消息驱动,不必自己去循环等待,此即异步选择机制。
3.异步选择机制中的重要函数WSAAsyncSelect(&)
&&&&&int&WSAAsyncSelect(&SOCKET&&&&&&&&s,
&&&&&&&&&&&&&&&&&&&&&&&&HWND&&&&&hWnd,
&&&&&&&&&&&&&&&&&&&&&&&&&unsigned&int&wMsg,
&&&&&&&&&&&&&&&&&&&&&&&&&&long&&&&&&&&lEvent)
&&&&&wMsg:套接字消息,如,该消息通过以下方式定义
&&&&&&&&&&&&#+
&&&&&lEvent:套接字事件,事件类型有:
&&&&&FD_READ:有数据接收
&&&&&FD_WRITE:有数据可以发送
&&&&&FD_ACCEPT:有客户建立连接
&&&&&FD_CONNECT:与服务器建立连接,或连接失败
&&&&&FD_CLOSE:连接被关闭
&&&&&FD_OOB:带外(紧急)数据到达
&&&&函数功能及使用方法说明:该函数用于将指定的套接字上发生的指定消息
及事件向指定的窗口注册。当套接字上发生指定事件时,系统会通过消息机制通
知指定的窗口函数处理。
&&&&利用函数向系统注册一个或多个套接字事件,如
WSAASyncSelect(s,hWnd,UM_SOCK,FD_READ|FD_ACCEPT|FD_CLOSE);
当窗口收到套接字消息后,函数将被触发,此时传入的参数中为,事件用通知,发生事件的套接字标识符由通知。
不同作用的套接字上注册的事件可能不同,它们可能都会注册事件,得到数据到达的通知。而主套接字上注册事件,从套接字上注册等事件,客户套接字则主要注册事件。
值得注意的是,使用了WSAASyncSelect的套接字自动变为非阻塞状态,这一点与select不同。
三、同步异步选择机制应用实例解析
1.设计步骤及关键思路
1.1设计基于同步选择机制的消息驱动程序
(1)一个窗口程序的基本框架
&&WinMain()&{
&&&RegisterClass();&&&//Initiate
&&&CreatWindow();&&&&
&&&ShowWindow();
&&&UpdataWindow();
&&&While(GetMessage(&msg))&{
&&&&&TranslateMessage();
&&&&&DispatchMessage();
&&WndProc(msg)&{
&&&swtich(msg)&{
case&WM_CREATE:
&&&Initiate&the&user&
case&WM_DESTROY:
&&&PostQuitMessage();
case&WM_START:
&&&StartServer();
default&DefWindowProc();&
(2)基于同步选择机制的准备工作
&&struct&socket_list&{
SOCKET&MainS
SOCKET&sock_array[SIZE];
&&void&init_list(socket_list&*list);&&//初始化管理队列
&&void&insert_list(SOCKET&s,sock_list&*list);&//管理队列插入函数
&&void&delete_list(SOCKET&s,sock_list&*list);&//管理队列删除函数
&&void&make_fdlist(socket_list&*list,fd_set&*fd_list);&//管理队列生成函数
(3)通信程序基本框架移植
&&void&InitServer(HWND&hWnd)&{
sockaddr_in&
unsigned&long&
WSAStartup(0x101,&wsa);
sock&=&socket(AF_INET,SOCK_STREAM,0);
if(sock&==&SOCKET_ERROR){
MessageBox(hWnd,&socket()&failed&,&server&,MB_OK);
server.sin_family&=&AF_INET;
server.sin_addr.S_un.S_addr&=&htonl(INADDR_ANY);
server.sin_port&=&htons(0x1234);
bind(sock,(sockaddr*)&server,sizeof(server));
listen(sock,5);
/*set&the&socket&to&nonbolck&*/
ioctlsocket(sock,FIONBIO,&arg);
init_list(&sock_list);
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
sock_list.MainSock&=&
&&void&StartServer(HWND&hWnd)&{
sockaddr_in&remote_
timeout.tv_sec&=&1;
timeout.tv_usec&=&0;
make_fdlist(&sock_list,&readfds);
make_fdlist(&sock_list,&writefds);
make_fdlist(&sock_list,&exceptfds);
retval&=&select(0,&readfds,&writefds,&exceptfds,&timeout);
if(retval&==&SOCKET_ERROR){
retval&=&WSAGetLastError();
if(FD_ISSET(sock_list.MainSock,&readfds)){
len&=&sizeof(remote_addr);
sock&=&accept(sock_list.MainSock,(sockaddr*)&remote_addr,&len);
if(sock&==&SOCKET_ERROR){
MessageBox(hWnd,&accept()&failed&,&server&,MB_OK);
MessageBox(hWnd,&&accept&a&connection&,&server&,MB_OK);
insert_list(sock,&sock_list);
for(i&=&0;i&&&64;i++){
if(sock_list.sock_array[i]&==&0)
sock&=&sock_list.sock_array[i];
if(FD_ISSET(sock,&readfds)){
retval&=&recv(sock,buf,128,0);
if(retval&==&0){
closesocket(sock);
MessageBox(hWnd,&&close&a&socket&,&server&,MB_OK);
delete_list(sock,&sock_list);
}else&if(retval&==&-1){
retval&=&WSAGetLastError();
if(retval&==&WSAEWOULDBLOCK)
closesocket(sock);
MessageBox(hWnd,&close&a&socket&of&error&,&server&,MB_OK);
delete_list(sock,&sock_list);
//printf&buf
hdc&=&GetDC(hWnd);
TextOut(hdc,0,row,buf,retval);
row&+=&16;
ReleaseDC(hWnd,hdc);
//send&ack
send(sock,&ACK&,3,0);
//if(FD_ISSET(sock,&writefds)){
//if(FD_ISSET(sock,&exceptfds)){
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptfds);
(4)细节完善
&&switch&(message)& {
case&WM_COMMAND:
wmId&&&&=&LOWORD(wParam);&
wmEvent&=&HIWORD(wParam);&
//&Parse&the&menu&selections:
switch&(wmId)&{
case&IDM_ABOUT:
&&&DialogBox(hInst,&(LPCTSTR)IDD_ABOUTBOX,&hWnd,&(DLGPROC)About);
case&IDM_EXIT:
&&&DestroyWindow(hWnd);
case&IDM_START:
StartServer(hWnd);
&&&return&DefWindowProc(hWnd,&message,&wParam,&lParam);
case&WM_PAINT:
hdc&=&BeginPaint(hWnd,&&ps);
//&TODO:&Add&any&drawing&code&here...
GetClientRect(hWnd,&&rt);
// DrawText(hdc,&szHello,&strlen(szHello),&&rt,&DT_CENTER);&
DrawText(hdc,&&Helloyou&,&8,&&rt,&DT_CENTER);&
EndPaint(hWnd,&&ps);
case&WM_DESTROY:
PostQuitMessage(0);
case&WM_CREATE:
InitServer(hWnd);
return&DefWindowProc(hWnd,&message,&wParam,&lParam);
return&DefWindowProc(hWnd,&message,&wParam,&lParam);
&&&return&0;
(5)调试与运行
图机制服务器接受客户连接
图机制服务器窗口陷入未响应状态
图服务器实现多路复用,与多客户机正常通信
1.2问题确定与改良方案
(1)问题表象
&&&&启动服务器程序,与客户机连接后,能够实现多路复用,但窗口无响应。
(2)问题本质
&&&&陷入了通信流程事件等待与处理的循环,无法返回窗口主程序。
(3)模块修正方案
&&&&去循环化,引入异步选择机制,使用进行事件注册。
1.3设计基于异步选择机制的消息
(1)去循环后的程序结构
主程序框架与同步选择机制相同,但有两处重要改动需十分注意:
第一,中的函数部分全部都移植到中,这样在点击菜单时,才能够监听连接,这与之前基于同步机制的服务器一开始运行就监听连接不同;
第二,将有连接请求、有数据到来、有数据发送等事件作为消息处理,以便机制能够更好地发挥作用。并且如此一来也不需要做循环,只需等待消息通知即可。
(2)WSAAsynSelect()的放置位置和时机
第一,在函数中监听后立刻使用:
if(listen(sock,5)&!=&0){
closesocket(sock);
WSACleanup();
MessageBox(hWnd,&listen()&failed\n&,&server&,MB_OK);
PostQuitMessage(0);
if(WSAAsyncSelect(sock,hWnd,UM_SOCK,FD_ACCEPT)&==&SOCKET_ERROR){
MessageBox(hWnd,&WSAAsyncSelect&failed\n&,&server&,MB_OK);
这样的好处是一旦有连接请求出现,函数就能够注册事件并通知主套接字,使之能够及时处理该事件。
第二,在函数中的判决内使用:
switch&(message)&
&&&&&&······
case&UM_SOCK:
s&=&(SOCKET)wP
wmEvent&=&LOWORD(lParam);
switch(wmEvent){
case&FD_ACCEPT:
&&len&=&sizeof(remote);
&&ns=&accept(s,&remote,&len);
&&&&&&&&&&&&WSAAsynSelect(ns,hWnd,UM_SOCK,FD_READ|FD_CLOSE); &&&&&
case&FD_READ:
retval&=&recv(s,recvbuf,sizeof(recvbuf),0);
if(retval&&=&0){
closesocket(s);
recvbuf[retval]&=&0;
hdc&=&BeginPaint(hWnd,&&ps);
hdc&=&GetDC(hWnd);
TextOut(hdc,0,row,recvbuf,strlen(recvbuf));
row&+=&16;
ReleaseDC(hWnd,hdc);
//回送信息
send(s,&ACK&,3,0);
case&FD_CLOSE:
MessageBox(hWnd,&closesocket\n&,&server&,MB_OK);
closesocket(s);
case&FD_WRITE:
MessageBox(hWnd,&write&event\n&,&server&,MB_OK);
if(WSAGETSELECTERROR(lParam)&!=&0){
MessageBox(hWnd,&select&report&error\n&,&server&,MB_OK);
closesocket(s);
WSACleanup();
return&DefWindowProc(hWnd,&message,&wParam,&lParam);
接着刚才的思路,由于异步选择机制的通知作用,主套接字上会在处做出对应的事件处理:ns=&accept(s,&remote,&len);
并且紧接下来就要进行新的事件注册:是否有读事件或是关闭套接字事件发生。如果有新的事件在套接字上发生,则在下一轮处理中做出事件响应。
(3)调试与运行
图异步选择机制服务器主界面
图连接客户机后服务器仍能响应窗口
图服务器实现多路复用,与多客户机正常通信
2.重要结论说明
(1)基于同步选择机制的通信服务器程序过于依赖循环结构,在于消息驱动机制结合时会存在固有冲突:对窗口的响应和对通信流程的处理。因此,通过同步机制的程序设计是对异步选择机制的一个很好地引入,也清楚地解释了异步响应为什么成为了设计消息驱动程序的一个很好的解决方案。
(2)WSAAsynSelect()函数是一次注册,若事件得到处理,那么之后的事件也会及时通知。然而若通知的事件没有被处理,那么不仅该事件不会重复通知,之后(在该套接字上)到来的所有事件都将得不到通知,除非之前通知的事件得到处理,也叫做事件使能。
(3)WSAAsynSelect()函数必须被正确地放置,才能够保证通信流程按照正常的顺序推进,如果函数位置设计不合理,则可能造成通信失败或者窗口无法关闭等。
()无论是同步选择机制还是异步选择机制,对于阻塞的处理都必须格外注意,尤其是在异步选择机制中。即便使用了函数,因为诸如函数等而阻塞也会导致窗口不能响应。
四、异步选择机制总结
1.异步选择的错误处理
异步选择机制需要做更多的错误处理,原因是:基于消息驱动的程序机制,一般来说有多个入口,而程序设计者并不知道使用者将在何时选择哪个入口,而这种随机性可能对程序流造成意想不到的破坏。
欲防止灾难性的错误发生,在程序设计时可采用两种方案:第一,迫使用户按照程序设计者规定的流程来操作,在每个阶段可将不需要的操作选项失效;第二,进行更多的错误判断,是进入每一个入口的条件更加严格。
2.异步选择与多路复用的联系
&&&Windows异步选择机制中,在通知用户的消息中,也同时产生了事件的套接字描述符,所以有以下结论:
第一,异步选择机制支持多路复用,即可以对多个套接字同时进行时间注册并同时处理;
第二,不同于的严格的管理队列设计,自行管理套接字队列的功能不是异步选择机制所必需的;
第三,下的多路复用由系统支持,但同时也受到系统限制;
第四,对于大型复杂服务器程序,仍需考虑对套接字队列的管理,甚至要慎重考虑是否需建立在窗口机制下。
3.异步选择与同步选择的对比
异步选择机制与同步选择机制的相同点与不同点列举出如下表所示:
基于的同步选择机制
WSAAsyncSelect异步选择机制
都是事件驱动机制,都支持多路复用
·不断查询
·使用了的套接字是否阻塞及阻塞时间与参数设计有关
·程序框架是不断循环
·同步性:查询结果是套接字当前状态
·需要用户自行管理套接字队列以备查询
·不存在事件使能:即如果不处理查询得到的事件,下次查询时事件依然存在
·一次注册
·使用的套接字是自动变成非阻塞状态的
·程序框架中尽量不出现循环
·异步性:不保证通知用户事件后用户能及时处理
·用户不必管理套接字队列,通知中包含套接字标识符
·存在事件使能:即如果不对本次通知的事件进行处理,那么后续事件也将不再通知,直到完成对本事件的处理
表同步选择机制与异步选择机制的异同对比
[1]段景山异步消息机制
[2]段景山窗口程序设计中的事件驱动,程序基本概念
[3]段景山多路通信与阻塞与非阻塞机制
[4]尹圣雨网络编程北京:人民邮电出版社,
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:618次
排名:千里之外君,已阅读到文档的结尾了呢~~
铁路防灾安全系统数据管理及客户端原型工具的设计,原型系统,铁路订票系统,铁路订票系统12306,铁路网上订票系统,铁路购票系统,铁路系统,铁路投资控制系统,铁路货运查询系统,铁路系统招聘
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
铁路防灾安全系统数据管理及客户端原型工具的设计
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口

我要回帖

更多关于 异步处理机制 的文章

 

随机推荐