第三章 WINDOWS SOCKETS 1.docx

上传人:b****8 文档编号:10447578 上传时间:2023-02-11 格式:DOCX 页数:79 大小:100.31KB
下载 相关 举报
第三章 WINDOWS SOCKETS 1.docx_第1页
第1页 / 共79页
第三章 WINDOWS SOCKETS 1.docx_第2页
第2页 / 共79页
第三章 WINDOWS SOCKETS 1.docx_第3页
第3页 / 共79页
第三章 WINDOWS SOCKETS 1.docx_第4页
第4页 / 共79页
第三章 WINDOWS SOCKETS 1.docx_第5页
第5页 / 共79页
点击查看更多>>
下载资源
资源描述

第三章 WINDOWS SOCKETS 1.docx

《第三章 WINDOWS SOCKETS 1.docx》由会员分享,可在线阅读,更多相关《第三章 WINDOWS SOCKETS 1.docx(79页珍藏版)》请在冰豆网上搜索。

第三章 WINDOWS SOCKETS 1.docx

第三章WINDOWSSOCKETS1

第三章WindowsSockets1.1应用实例

在本章中,作者的实际工作为背景,给出了一个使用WindowsSockets1.1编程的具体例子。

并对这个例子作了详细的分析。

这个例子在Windows3.1、WindowsSockets1.1和BSDOSforPC2.0(BSDUNIX微机版)环境下调试通过。

3.1套接口网络编程原理

套接口有三种类型:

流式套接口,数据报套接口及原始套接口.

流式套接口定义了一种可靠的面向连接的服务,实现了无差错无重复的顺序数据传输.数据报套接口定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错.原始套接口允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等.

无连接服务器一般都是面向事务处理的,一个请求一个应答就完成了客户程序与服务程序之间的相互作用。

若使用无连接的套接口编程,程序的流程可以用图3-1表示。

面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的,而且往往是并发服务器。

使用面向连接的套接口编程,可以通过图3-1来表示:

其时序。

套接口工作过程如下:

服务器首先启动,通过调用socket()建立一个套接口,然后调用bind()将该套接口和本地网络地址联系在一起,再调用listen()使套接口做好侦听的准备,并规定它的请求队列的长度,之后就调用accept()来接收连接.客户在建立套接口后就可调用connect()和服务器建立连接.连接一旦建立,客户机和服务器之间就可以通过调用read()和write()来发送和接收数据.最后,待数据传送结束后,双方调用close()关闭套接口.

3.2WindowsSockets编程原理

由于Windows的基于消息的特点,WINSOCK和BSD套接口相比,有如下一些新的扩充:

1.异步选择机制

异步选择函数WSAAsyncSelect()允许应用程序提名一个或多个感兴趣的网络事件,如FD_READ,FD_WRITE,FD_CONNECT,FD_ACCEPT等等代表的网络事件.当被提名的网络事件发生时,Windows应用程序的窗口函数将收到一个消息.这样就可以实现事件驱动了.

2.异步请求函数

异步请求函数允许应用程序用异步方式获得请求的信息,如WSAAsyncGetXByY()类函数.这些函数是对BSD标准函数的扩充.函数WSACancelAsyncRequest()允许用户中止一个正在执行的异步请求.

3.阻塞处理方法

WINSOCK提供了"钩子函数"负责处理Windows消息,使Windows的消息循环能够继续.WINSOCK提供了两个函数(WSASetBlockingHook()和WSAUnhookBlockingHook())让应用程序设置或取消自己的"钩子函数".函数WSAIsBlocking()可以检测是否阻塞,函数WSACancelBlockingCall()可以取消一个阻塞的调用.

4.错误处理

WINSOCK提供了两个WSAGetLastError()和WSASetLastError()来获取和设置最近错误号.

5.启动和终止

由于WindowsSockets的服务是以动态连接库WINSOCK.DLL形式实现的,所以必须要先调用WSAStartup()函数对WindowsSocketsDLL进行初始化,协商WINSOCK的版本支持,并分配必要的资源.在应用程序关闭套接口后,还应调用WSACleanup()终止对WindowsSocketsDLL的使用,并释放资源,以备下一次使用.

在这些函数中,实现Windows网络实时通信的关键是异步选择函数WSAAsyncSelect()的使用.用法及详细说明参见第5.3.7.

3.3WindowsSockets与UNIX套接口编程实例

下面是一个简单的基于连接的点对点实时通信程序.它由两部分组成,服务器在主机UNIX下直接运行,客户机在Windows下运行.

3.3.1SERVER介绍

由于SERVER是在UNIX下运行的,它对套接口的使用都是BSD的标准函数,程序也比较简单,只有一段程序,下面简要解释一下.

首先,建立自己的套接口.在互连网的进程通信中,全局标识一个进程需要一个被称为"半相关"的三元组(协议,本地主机地址,本地端口号)来描述,而一个完整的进程通信实例则需要一个被称为"相关"的五元组(协议,本地主机地址,本地端口号,远端主机地址,远端端口号)来描述.

s=socket(AF_INET,SOCK_STREAM,0)

该函数建立指定地址格式,数据类型和协议下的套接口,地址格式为AF_INET(唯一支持的格式),数据类型SOCK_STREAM表示建立流式套接口,参数三为0,即协议缺省.

bind(s,(structsockaddr*)&server,sizeof(server))

该函数将建立服务器本地的半相关,其中,server是sockaddr_in结构,其成员描述了本地端口号和本地主机地址,经过bind()将服务器进程在网上标识出来.

然后,建立连接.先是调用listen()函数表示开始侦听.再通过accept()调用等待接收连接.

listen(s,1)表示连接请求队列长度为1,即只允许有一个请求,若有多个请求,则出现错误,给出错误代码WSAECONNREFUSED.

ns=accept(s,(structsockaddr*)&client,&namelen))

accept()阻塞(缺省)等待请求队列中的请求,一旦有连接请求来,该函数就建立一个和s有相同属性的新的套接口.client也是一个sockaddr_in结构,连接建立时填入请求连接的套接口的半相关信息.

接下来,就可以接收和发送数据了.

recv(ns,buf,1024,0)

send(ns,buf,pktlen,0)

上面两个函数分别负责接收和发送数据,recv从ns(建立连接的套接口)接收数据放入buf中,send则将buf中数据发送给ns.至于第四个参数,表示该函数调用方式,可选择MSG_DONTROUTE和MSG_OOB,0表示缺省.

最后,关闭套接口.

close(ns);

close(s);

3.3.2CLIENT介绍

客户端是在Windows上运行的,使用了一些WindowsSockets的扩展函数,稍微复杂一些.包括了.RC和.C两个文件,其中的主窗口函数ClientProc()是程序的主要部分,下面简单解释一下.

首先,是在WinMain()中建立好窗口后,即向主窗口函数发一条自定义的WM_USER消息,做相关的准备工作.在主窗口函数中,一接收到WM_USER消息,首先调用WSAStartup()函数初始化WindowsSocketsDLL,并检查版本号.如下:

Status=WSAStartup(VersionReqd,lpmyWSAData);

其中,VersionReqd描述了WINSOCK的版本(这里为1.1版),lpmyWSAData指向一个WSADATA结构,该结构描述了WindowsSockets的实现细节.

WSAStartup()之后,进程通过主机名(运行时命令行参数传入)获取主机地址,如下:

hostaddr=gethostbyname(server_address);

hostaddr指向hostent结构,内容参见5.2.1.

然后,进程就不断地消息循环,等待用户通过菜单选择"启动".这时,通过调用Client()来启动套接口.在Client()中,首先也是调用socket()来建立套接口.如下:

if((s=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)

{

AlertUser(hWnd,"SocketFailed");

return(FALSE);

}

紧接着,调用WSAAsyncSelect()函数提名FD_CONNECT网络事件,如下:

if(!

SetSelect(hWnd,FD_CONNECT))

return(FALSE);

SetSelect()主要就是调用WSAASyncSelect(),让WindowsSocketsDLL在侦测到连接建立时,就发送一条UM_SOCK的自定义消息,使消息循环继续下去.如下:

BOOLSetSelect(HWNDhWnd,longlEvent)

{

if(WSAAsyncSelect(s,hWnd,UM_SOCK,lEvent)==SOCKET_ERROR)

{

AlertUser(hWnd,"WSAAsyncSelectFailure.");

return(FALSE);

}

return(TRUE);

}

为建立连接,必须马上调用connect()如下,由于先调用了WSAASyncSelect(),connect()便是非阻塞调用.进程发出连接请求后就不管了,当连接建立好后,WINSOCKDLL自动发一条消息给主窗口函数,以使程序运行下去.

connect(s,(structsockaddrFAR*)&dst_addr,sizeof(dst_addr));

窗口函数在收到UM_SOCK消息后,判断是由哪个网络事件引起的,第一次,必然是由连接事件引起的,这样,就会执行相应的程序段,同样调用SetSelect()来提名FD_WRITE事件.希望在套接口可发送数据时接到消息.在收到FD_WRITE消息时,先调用send()发送数据,再调用SetSelect()来提名FD_READ事件,希望在套接口可接收数据是接到消息.在收到FD_READ消息时,先调用recv()来接收数据再提名FD_WRITE事件,如此循环下去.直到发生连接关闭的事件FD_CLOSE,这时就调用WSAAsyncSelect(s,hWnd,0,0)来停止异步选择.在窗口函数接到WM_DESTROY消息时(即关闭窗口之前),先调用closesocket()(作用同UNIX中的close())来关闭套接口,再调用WSACleanup()终止WindowsSocketsDLL,并释放资源.

3.3.3源程序清单

程序1:

CLIENT.RC

ClientMenuMENU

BEGIN

POPUP"&Server"

BEGIN

MENUITEM"&Start...",101

MENUITEM"&Exit",102

END

END

程序2:

CLIENT.C

#defineUSERPORT10001

#defineIDM_START101

#defineIDM_EXIT102

#defineUM_SOCKWM_USER+0X100

#include

#include

#include

#include

#defineMAJOR_VERSION1

#defineMINOR_VERSION2

#defineWSA_MAKEWORD(x,y)((y)*256+(x))

HANDLEhInst;

charserver_address[256]={0};

charbuffer[1024];

charFAR*lpBuffer=&buffer[0];

SOCKETs=0;

structsockaddr_indst_addr;

structhostentfar*hostaddr;

structhostenthostnm;

structserventfar*sp;

intcount=0;

BOOLInitApplication(HINSTANCEhInstance);

longFARPASCALClientProc(HWNDhWnd,unsignedmessage,UINTwParam,LONGlParam);

voidAlertUser(HWNDhWnd,char*message);

BOOLClient(HWNDhWnd);

BOOLReceivePacket(HWNDhWnd);

BOOLSetSelect(HWNDhWnd,longlEvent);

BOOLSendPacket(HWNDhWnd,intlen);

intPASCALWinMain(HANDLEhInstance,HANDLEhPrevInstance,LPSTRlpCmdLine,intnCmdShow)

{

HWNDhWnd;

MSGmsg;

lstrcpy((LPSTR)server_address,lpCmdLine);

if(!

hPrevInstance)

if(!

InitApplication(hInstance))

return(FALSE);

hInst=hInstance;

hWnd=CreateWindow("ClientClass","WindowsECHOClient",WS_OVERLAPPEDWINDOW,\

CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\

hInstance,NULL);

if(!

hWnd)

return(FALSE);

ShowWindow(hWnd,nCmdShow);

UpdateWindow(hWnd);

PostMessage(hWnd,WM_USER,(WPARAM)0,(LPARAM)0);

while(GetMessage(&msg,NULL,NULL,NULL))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return(msg.wParam);

}

BOOLInitApplication(HINSTANCEhInstance)

{

WNDCLASSWndClass;

char*szAppName="ClientClass";

//fillinwindowclassinformation

WndClass.lpszClassName=(LPSTR)szAppName;

WndClass.hInstance=hInstance;

WndClass.lpfnWndProc=ClientProc;

WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);

WndClass.hIcon=LoadIcon(hInstance,NULL);

WndClass.lpszMenuName="ClientMenu";

WndClass.hbrBackground=GetStockObject(WHITE_BRUSH);

WndClass.style=CS_HREDRAW|CS_VREDRAW;

WndClass.cbClsExtra=0;

WndClass.cbWndExtra=0;

//registertheclass

if(!

RegisterClass(&WndClass))

return(FALSE);

return(TRUE);

}

longFARPASCALClientProc(HWNDhWnd,unsignedmessage,UINTwParam,LONGlParam)

{

intlength,i;

WSADATAwsaData;

intStatus;

switch(message)

{

caseWM_USER:

{

WORDwMajorVersion,wMinorVersion;

LPWSADATAlpmyWSAData;

WORDVersionReqd;

intret;

wMajorVersion=MAJOR_VERSION;

wMinorVersion=MINOR_VERSION;

VersionReqd=WSA_MAKEWORD(wMajorVersion,wMinorVersion);

lpmyWSAData=(LPWSADATA)malloc(sizeof(WSADATA));

Status=WSAStartup(VersionReqd,lpmyWSAData);

if(Status!

=0)

{

AlertUser(hWnd,"WSAStartup()failed\n");

PostQuitMessage(0);

}

hostaddr=gethostbyname(server_address);

if(hostaddr==NULL)

{

AlertUser(hWnd,"gethostbynameERROR!

\n");

WSACleanup();

PostQuitMessage(0);

}

_fmemcpy(&hostnm,hostaddr,sizeof(structhostent));

}

break;

caseWM_COMMAND:

switch(wParam)

{

caseIDM_START:

if(!

Client(hWnd))

{

closesocket(s);

AlertUser(hWnd,"StartFailed");

}

break;

caseIDM_EXIT:

//WSACleanup();

PostQuitMessage(0);

break;

}

break;

caseUM_SOCK:

switch(lParam)

{

caseFD_CONNECT:

if(!

SetSelect(hWnd,FD_WRITE))

closesocket(s);

break;

caseFD_READ:

if(!

ReceivePacket(hWnd))

{

AlertUser(hWnd,"ReceivePacketFailed.\n");

closesocket(s);

break;

}

if(!

SetSelect(hWnd,FD_WRITE))

closesocket(s);

break;

caseFD_WRITE:

for(i=0;i<1024;i++)

buffer[i]=(char)'A'+i%26;

length=1024;

if(!

SendPacket(hWnd,length))

{

AlertUser(hWnd,"PacketSendFailed!

\n");

closesocket(s);

break;

}

if(!

SetSelect(hWnd,FD_READ))

closesocket(s);

break;

caseFD_CLOSE:

if(WSAAsyncSelect(s,hWnd,0,0)==SOCKET_ERROR)

AlertUser(hWnd,"WSAAsyncSelectFailed.\n");

break;

default:

if(WSAGETSELECTERROR(lParam)!

=0)

{

AlertUser(hWnd,"SocketReportFailure.");

closesocket(s);

break;

}

break;

}

break;

caseWM_DESTROY:

closesocket(s);

WSACleanup();

PostQuitMessage(0);

break;

default:

return(DefWindowProc(hWnd,message,wParam,lParam));

}

return(NULL);

}

voidAlertUser(HWNDhWnd,char*message)

{

MessageBox(hWnd,(LPSTR)message,"Warning",MB_ICONEXCLAMATION);

return;

}

BOOLClient(HWNDhWnd)

{

memset(&dst_addr,'\0',sizeof(structsockaddr_in));

_fmemcpy((charFAR*)&dst_addr.sin_addr,(charFAR*)hostnm.h_addr,hostnm.h_length);

dst_addr.sin_family=hostnm.h_addrtype;

dst_addr.sin_port=htons(USERPORT);

if((s=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)

{

AlertUser(hWnd,"SocketFailed");

return(FALSE);

}

if(!

SetSelect(hWnd,FD_CONNECT))

return(FALSE);

connect(s,(structsockaddrFAR*)&dst_addr,sizeof(dst_addr));

return(TRUE);

}

 

BOOLReceivePacket(HWNDhWnd)

{

HDChDc;

intlength;

inti1,i2,i3;

charline1[255],line2[255],line3[255];

count++;

if((length=recv(s,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 小学教育 > 小升初

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1