操作系统课程设计 winsock+api编程.docx
- 文档编号:4700473
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:9
- 大小:21.09KB
操作系统课程设计 winsock+api编程.docx
《操作系统课程设计 winsock+api编程.docx》由会员分享,可在线阅读,更多相关《操作系统课程设计 winsock+api编程.docx(9页珍藏版)》请在冰豆网上搜索。
操作系统课程设计winsock+api编程
操作系统课程设计winsock+api编程
操作系统课程设计winsock+api编程操作系统课程设计学习WinsockAPI编程操作系统课程设计学习WinsockAPI编程班级:
信计0501姓名:
李宁学号:
305010400?
姓名:
宋若军学号:
3050104025学习WinsockAPI编程WindpowsSockets是广泛应用的、开放的、支持多种协议的网络编程接口,主要由winsock.h头文件和动态链接库winsock.dll组成。
一、套接字套接字(Sockes)是通信的基础,是支持TCP/IP协议的网络通信的基本操作单元。
可以将套接字看作是不同主机之间的进程进行双向通信的端点。
根据通信网络的特性,套接字可以分为以下两类。
1、流套接字流套接字提供没有边界的数据流(即字节流),能够确保数据流以正确的顺序无重复地被送达,使用于处理大量数据。
流套接字是面向连接的。
2、数据报套接字数据报套接字支持双向数据流,此数据流不能保证按顺序和不重复送达,也不能保证数据传输的可靠性。
数据报套接字是无连接的。
Winsock对有可能阻塞的函数提供了两种处理方式:
阻塞方式和非阻塞方式。
在阻塞方式下,收发数据的函数在被调用后一直等到传送完毕或出错才能返回,期间不能进行任何操作。
在非阻塞方式下,函数被调用后立即返回,当网络传送完后,由Winsock给应用程序发送一个消息,通知操作完成。
在编程时,应尽量使用非阻塞模式。
二、Winsock的启动和终止由于Winsock服务是以动态链接库的形式实现的,所以在使用前必须调用WSAStartup函数对其进行初始化,协商Winsock的版本支持,并分配必要的资源。
WSAStartup函数声明如下:
intWSAStartup(WORDwVersionRequested,LPWSADATAIpWSAData);参数说明:
◇wVersionRequested:
指定加载的Winsock版本,通常高位字节指定Winsock的副版本,低位字节指定Winsock的主版本,然后用MAKEWORD(X,Y)宏获取该值。
◇IpWSAData:
WSADATA数据结构指针,其中WSADATA结构的定义如下:
TypedefstructWSAData{WORDwVersion;//期望使用的Winsock版本WORDwHighVersion;//返回现有Winsock最高版本charszDescription[WSADESCRIPTION_LEN+1];//套接字实现描述、charszSystemStatus[WSASYS_STATUS_LEN+1];//状态或配置信息unsignedshortiMaxSockets;//最大套接字数unsignedshortiMaxUdpDg;//最大数据报长度charFAR*IpVendorInfo;//保留}WSADATA,FAR*LPWSADATA;在应用程序关闭套接字连接后,还需要调用WSACleanup函数终止对Winsock库的使用,并释放资源,函数声明如下:
intWSACleanup(void);三、Winsock编程模型不论是流套接字还是数据报套接字编程,一般都采用客户端/服务器模式,其运行原理基本类似。
数据报套接字的编程模型如图一所示。
流套接字的编程模型如图二所示。
服务器socket()bind()closesocket()recvfrom()sendto()socket()客户端closesocket()recvfrom()sendto()服务器socket()bind()listen()accept()send()recv()closesocket()socket()connect()closesocket()send()recv()客户端图一数据报套接字编程模型图二流套接字编程模型流套接字的服务进程和客户端进程在通信前必须创建各自的套接字并建立连接,然后才能实现数据传输。
具体编程步骤如下:
(1)服务器进程创建套接字。
(2)将本地地址绑定到套接字上以标识该套接字。
(3)将套接字置入监听模式并准备接收连接请求。
(4)客户端进程调用socket函数创建客户端套接字。
(5)客户端进程向服务进程发出连接请求。
(6)数据传输。
(7)关闭套接字。
服务器进程总是先于客户进程启动,调用socket创建一个流套接字,该函数声明如下:
SOCKETsocket(intaf,inttype,intprotocol);参数说明:
◇af:
指定网络地址族,一般为AF_INET。
◇type:
指定套接字类型,可选的取值如下:
△SOCK_STREAM流套接字。
△SOCK_DGRAM数据报套接字。
◇protocol:
指定网络协议,一般为0,表示默认的TCP/IP协议。
成功创建了Socket之后,就应该选定通信的对象。
调用bind()函数可以将本地地址绑定到套接字上,该函数声明如下:
intbind(SOCKETs,conststructsockaddtFAR*name,intnamelen);参数说明:
◇s:
指定一个未绑定的套接字句柄,用于等待客户进程的连接。
◇name:
指向sockaddr结构对象的指针。
◇namelen:
指定sockaddr结构的长度。
其中sockddr结构随选择的协议的不同而变化,因此常用的是sockaddr_in结构,用来标识TCP/IP协议下的地址,该结构定义如下:
structsockaddr_in{shortsin_family;//指定地址族,一般为AF_INETu_shortsin_port;//指定端口号structin_addrsin_addr;//指定IP地址charsin_zero[8];//填充位};其中IP地址结构in_addr的定义如下:
structin_addr{union{struct{u_chars_b1,s_b2,s_b3,s_b4;}S_un_b;struct{u_shorts_w1,s_w2;}S_un_w;u_longS_addr;}S_un;};绑定成功后,调用listen函数用于设置套接字的等待连接状态,该函数声明如下:
intlisten(SOCKETs,intbacklog);参数说明:
◇s:
指定一个已绑定未连接的套接字句柄。
◇backlog:
指定正在等待连接的队列的最大长度,可取1~5。
进入监听状态后,通过调用accept函数使套接字做好接受客户连接的准备,该函数声明如下:
SOCKETaccept(SOCKETs,structsockaddrFAR*addr,intFAR*addrlen);参数说明:
◇s:
指定处于监听状态的套接字句柄。
◇addr:
指定一个有效的SOCKADDR_IN结构地址。
◇addrlen:
指定SOCKADDR_IN结构的长度。
accept函数返回后,addr变量中会包含请求连接的客户IP地址,并返回一个新的套接字句柄,对应于已经接受的那个客户端连接。
而原来的监听套接字仍处于监听状态。
客户进程调用connect函数可以主动提出连接请求,该函数声明如下:
intconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen);参数说明:
◇s:
指定一个未连接的套接字句柄。
◇name:
指定服务进程的IP地址信息,针对TCP协议。
◇namelen:
指定name参数的长度。
当服务器进程接受连接请求后,将生成一个新的套接字,并向各客户进程返回接受信号。
一旦客户进程收到来自服务器的接受信号,表示建立连接,即可进行数据传输了。
调用send函数用于发送数据,调用recv函数用于接受数据,函数声明如下:
intsend(SOCKETs,constcharFAR*buf,intlen,intflags);intrecv(SOCKETs,constcharFAR*buf,intlen,intflags);参数说明◇s:
指定已建立连接的套接字。
◇buf:
发送或接受数据缓冲区。
◇len:
指定数据缓冲区的长度。
◇flags:
标志,一般为0。
通信结束,必须关掉连接以释放套接字占用的资源。
调用closesocket函数用于关闭套接字,该函数声明如下:
Intclosesocket(SOCKETs);为了保证套接字正常关闭,一般在调用closesocket之前先调用shutdown函数中断连接。
该函数声明如下:
intshutdown(SOCKETs,inthow);参数说明:
◇s:
指定要中断的套接字句柄。
◇how:
指定将禁止的操作,可选的取值如下:
△SD_RECEIVE禁止调用接受函数。
△SD_SEND禁止调用发送函数。
△SD_BOTH取消收发操作。
四、WinsockI/O模型Winsock套接字在两种模式下执行I/O操作,即阻塞和非阻塞。
默认情况下,套接字为阻塞模式。
下面的代码演示了创建一个套接字,并将其设置为非阻塞模式的过程:
SOCKETs;//套接字句柄unsignedlongcmd;//指令参数intnStatus;//返回值s=socket(AF_INET,SOCK_STREAM,0);//创建流套接字nStatus=ioctlsocket(s,FIOBIO,//设置为非阻塞模式将一个套接字设置为非阻塞模式之后,WinsockAPI调用会立即返回。
Winsock提供了几种不同的套接字I/O模型,如选择(Select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)和重叠(Overlapped)等。
1.WSAAsyncSelect模型利用异步选择模型,应用程序可以在一个套接字上接收以Windows消息为基础的网络事件通知。
该模型的实现方法是通过调用WSAAsyncSelect函数自动将套接字设置为非阻塞模式,并注册一个或多个网络事件,提供一个消息通知的窗口句柄。
当注册的网络事件发生时,对应的窗口将接收到一个基于消息的通知。
WSAAsyncSelect函数声明如下:
intWSAAsyncSelect(SOCKETs,HWNDhWnd,unsignedintwMsg,longIEwent);参数说明:
◇s:
指定需要事件通知的套接句柄。
◇hWnd:
指定接收消息的窗口句柄。
◇wMsg:
指定发送的消息。
◇IEvent:
指定网络事件集合,可以是以下取值的和:
△FD_READ想要接收读准备好的通知。
△FD_WRITE想要接收写准备好的通知。
△FD_OOB想要接收带外数据到达的通知。
△FD_ACCEPT想要接收连接准备好的通知。
△FD_CONNECT想要接收已经连接的通知。
△FD_CLOSE想要接收套接字关闭的通知。
如果要取消所有的通知,则将IEvent参数设置为0即可。
2.WSAEventSelect模型与异步选择模型相似,利用事件选择模型应用程序可以在一个或多个套接字上接收以事件为基础的网络事件通知,并且它支持的网络事件与异步选择模型一样。
它与WSAAsyncSelect模型最主要的区别在于,网络事件会被发送到一个事件对象句柄,而不是一个窗口句柄。
首先需要调用WSACreateEvent函数创建事件对象来接收网络事件,该函数声明如下:
WSAEVENTWSACreateEvent(void);返回的事件对象具有两种工作状态:
有信号和无信号。
接着调用WSAEventSelect函数将所创建的事件对象与套接字关联起来,并注册网络事件,该函数声明如下:
IntWSAEventSelect(SOCKETs,WSAEVENThEventObject,LongINetworkEvents);参数说明:
◇s:
指定需要事件通知的套接字句柄。
◇hEventObject:
指定事件对象句柄。
◇InetworkEvent:
指定网络事件集合。
在完成一个I/O操作之后应用程序需要调用WSAResetEvent函数重置该事件对象,函数声明如下:
BOOLWSAResetEvent(WSAEVENThEvent);参数说明◇hEvent:
用于指定事件对象句柄。
一个套接字与一个事件对象句柄关联起来之后,应用程序就可以通过WSAWaitForMultipleEvents函数等待网络事件来触发事件句柄的工作状态,进行I/O操作,该函数声明如下:
DWORDWSAWaitForMultipleEvents(DWORDcEvents,constWSAEVENTFAR*IphEvents,BOOLfWaitAll,DWORDdwTimeOUT,BOOLfAlertable);参数说明:
◇cEvent:
指定事件对象句柄数组的元素的个数。
、◇IphEvents:
指向一个事件对象句柄数组的指针。
◇fWaitAll:
指定是否等待所有事件对象同时有信号。
◇dwTimeOUT:
指定超时等待时间。
◇fAlertable:
指定当系统将I/O例程放入队列时,函数是否返回。
五、应用实例:
基于WinsockAPI调用的聊天室1、服务器端应用程序设计
(1)首先建立一个空的工作空间E1701。
(2)在空间E1701里建立一个对话框工程Server作为服务端。
对话框设计如图三所示。
图三服务器端窗口设计(3)在类CServerDlg中给显示聊天内容和发送聊天内容的文本框添加变量//DialogData//{{AFX_DATA(CServerDlg)enum{IDD=IDD_SERVER_DIALOG};CEditm_Show;//聊天记录显示控件对象CStringm_strShow;//聊天记录字符串CStringm_strMsg;//聊天内容字符串//}}AFX_DATA(4)在服务器端要保存客户端的socket连接,故引入链表支持,在ServerDlg.h中添加代码:
#includetypedefCListSOCKET_ARRAY;(5)要调用WinsockAPI必须包含winsock.h头文件和动态链接库winsock.dll。
在StdAfx.h文件中添加如下代码:
#include#pragmacomment(lib,“wsock32.lib“)(6)自定义消息,并添加消息处理函数。
在Server.h中添加:
#defineWM_SERVERMSG(WM_USER+100)//Generatedmessagemapfunctions//{{AFX_MSG(CServerDlg)afx_msglongOnServerMsg(WPARAMwParam,LPARAMlParam);//}}AFX_MSG(7)初始化服务器窗口,创建服务器端socket。
BOOLCServerDlg:
:
OnInitDialog(){CDialog:
:
OnInitDialog();//TODO:
Addextrainitializationheretry{WSADATAwsaData;//WSADATA结构对象WORDwVersionRequested=MAKEWORD(2,0);//指定Winsock版本为2.0WSAStartup(wVersionRequested,//启动Winsockm_hSocket=socket(AF_INET,SOCK_STREAM,0);//创建流套接字UINTlen=WSAGetLastError();//获取错误代码if(len!
=0)throwlen;//抛出异常错误m_saList.RemoveAll();//清空套接字列表WSAAsyncSelect(m_hSocket,this->m_hWnd,//接收消息的窗口为对话框WM_SERVERMSG,//指定消息FD_ACCEPT|FD_READ|FD_WRITE|FD_CLOSE);//指定事件m_uPort=8080;//设置端口号//设置套接字地址结构对象m_addr.sin_family=AF_INET;m_addr.sin_addr.S_un.S_addr=INADDR_ANY;m_addr.sin_port=htons(m_uPort);bind(m_hSocket,(LPSOCKADDR)//绑定套接字listen(m_hSocket,3);//进入监听状态len=WSAGetLastError();if(len!
=0)throwlen;m_strShow=_T(“服务器启动成功……“);}catch(UINTm_strShow=_T(“创建套接字失败!
“);break;caseWSAEINVAL:
MessageBox(“监听端口已被占用!
“);m_strShow=_T(“服务器启动失败“);break;default:
MessageBox(“监听端口已被占用!
“);m_strShow=_T(“服务器启动失败“);}}UpdateData(FALSE);//更新显示returnTRUE;}(8)修改OnDestroy()函数voidCServerDlg:
:
OnDestroy(){CDialog:
:
OnDestroy();WSAAsyncSelect(m_hSocket,this->m_hWnd,0,0);//取消异步选择模式WSACleanup();//清理Winsock}(9)编写发送按钮函数voidCServerDlg:
:
OnButton1(){UpdateData(TRUE);m_strShow+=_T(“\r\n“);//回车、换行m_strShow+=m_strMsg;//添加聊天内容SOCKETs;for(inti=0;i#pragmacomment(lib,“wsock32.lib“)(4)自定义消息,并添加消息处理函数。
在Client.h中添加:
#defineWM_CLIENTMSG(WM_USER+200)//Generatedmessagemapfunctions//{{AFX_MSG(CClientDlg)afx_msglongOnClientMsg(WPARAMwParam,LPARAMlParam);//}}AFX_MSG(5)初始化客户端窗口,创建socket。
准备建立连接BOOLCClientDlg:
:
OnInitDialog(){//窗口初始化函数CDialog:
:
OnInitDialog();//TODO:
AddextrainitializationhereWSADATAwsaData;WORDwVersionRequested=MAKEWORD(2,0);WSAStartup(wVersionRequested,m_hSocket=socket(AF_INET,SOCK_STREAM,0);//调用socket函数创建套接字WSAAsyncSelect(m_hSocket,this->m_hWnd,WM_CLIENTMSG,FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE);//利用异步选择模型,自动设置为非阻塞模式returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}(6)编写连接按钮函数voidCClientDlg:
:
OnButton2(){UpdateData(true);BYTEf0,f1,f2,f3;m_ip.GetAddress(f0,f1,f2,f3);CStringaddr;addr.Format(“%d.%d.%d.%d“,f0,f1,f2,f3);m_addr.sin_family=AF_INET;m_addr.sin_addr.S_un.S_addr=inet_addr(addr.GetBuffer(0));m_addr.sin_port=htons(m_uPort);connect(m_hSocket,(LPSOCKADDR)//连接服务器UINTtt=WSAGetLastError();switch(tt){case10035:
break;default:
UpdateData(false);closesocket(this->m_hSocket);this->OnInitDialog();this->OnButton2();}}(7)编写发送函数voidCClientDlg:
:
OnButton1(){UpdateData(TRUE);m_strShow+=“\r\n“;m_strShow+=m_strMsg;send(m_hSocket,m_strMsg.GetBuffer
(1),m_strMsg.GetLength(),0);UINTtt=WSAGetLastError();if(tt!
=0){m_strShow+=“\r\n发送失败!
“;}m_strMsg.Empty();UpdateData(FALSE);}(8)重写OnDestroy()函数voidCClientDlg:
:
OnDestroy(){CDialog:
:
OnDestroy();WSAAsyncSelect(m_hSocket,this->m_hWnd,0,0);//取消异步选择模式WSACleanup();//关闭套接字,终止连接释放资源}(9)编写消息处理函数longCClientDlg:
:
OnClientMsg(WPARAMwParam,LPARAMlParam){charbuf[1024];intlen;switch(lParam){caseFD_CONNECT:
m_strShow=“连接到服务器……“;UpdateData(FALSE);return0;caseFD_READ:
len=recv(m_hSocket,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统课程设计 winsock+api编程 操作系统 课程设计 winsock api 编程
![提示](https://static.bdocx.com/images/bang_tan.gif)