VisualC++网络编程案例实战之网络通信器_第1页
VisualC++网络编程案例实战之网络通信器_第2页
VisualC++网络编程案例实战之网络通信器_第3页
VisualC++网络编程案例实战之网络通信器_第4页
VisualC++网络编程案例实战之网络通信器_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第7章网络通信器现在,有许多即时通信软件在大家的生活中非常常见,并且起着很大的作用。即时通信软件可以让用户之间快速地进行交流沟通,也正是因为这个原因使人们对即时通信软件的需求非常大,对其功能要求也很苛刻。在本章中,将向用户介绍实现即时通信功能的软件编程方法以及通信原理。7.1通信原理网络通信软件的数据通信是通过网络套接字进行的。根据该原理,其编程步骤应分为创立套接字、在套接字上进行收发数据、关闭套接字等操作。在这里需要用户注意:如果在效劳器端进行编程,成功创立套接字以后,需要将本地地址与端口号绑定到已经创立的套接字上。在VC中,创立基于对话框模式的应用程序,利用资源管理器对程序界面进行整理,使界面整齐、美观。但是,限于笔者的美工水平,所设计出来的程序界面仅供用户学习和参考,笔者主要讲述程序设计方法等。如果用户对界面不够满意,可以对随书光盘中的本实例界面重新进行设计。注意:用户在实际使用时,应该首先启动效劳器,然后再启动客户端。否那么,客户端将不能连接效劳器。7.1.1通信连接在通信软件初始化时,客户端连接效劳器的过程是该应用程序初始化的第一步,也是很重要的一步。客户端利用API函数创立套接字,需要对套接字库进行初始化。代码如下:01 ... //省略局部代码02 WSADATAdata; 03 DWORDss=MAKEWORD(2,0); //指定套接字库版本号04 ::WSAStartup(ss,&data); //初始化套接字库当程序正常退出或者遇到其他情况退出时,用户应该对已经初始化的套接字库进行释放。例如代码如下:01 ...//省略局部代码02 WSACleanup(); //释放套接字库1.创立套接字用户对套接字库初始化成功后,便可以调用前面所介绍的函数创立套接字了。对于效劳器和客户端而言,效劳器的套接字分为连接套接字和数据收发套接字。因为作为效劳器不可能只响应一个客户端的连接请求,所以创立连接套接字对所有的连接请求进行响应。下面,将分别向用户介绍创立客户端和效劳器端套接字的具体方法。〔1〕创立客户端套接字对于创立客户端套接字,需要用户指定协议类型。代码如下:01 ...//省略局部代码02 SOCKETs;//声明套接字对象03s=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); //创立套接字,并返回其句柄〔2〕创立效劳器套接字与客户端创立套接字不同。首先,效劳器需要创立一个专门用于响应客户端连接请求的连接套接字。然后,将该套接字与本地地址绑定在一起。最后,在该套接字上进行监听。代码如下:01 ...//省略局部代码02 SOCKADDR_INaddr;03 s1=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创立连接套接字对象04 addr.sin_family=AF_INET; //填充套接字地址结构05 addr.sin_port=htons(80);06 addr.sin_addr.S_un.S_addr=inet_addr(strIP);07 ::bind(s1,(sockaddr*)&addr,sizeof(addr)); //绑定套接字与本地地址08 ::listen(s,5); //监听套接字其中,变量strIP表示本地IP地址。用户可以通过gethostbyname()等函数获取本地IP地址。代码如下:01

charname[20]="";02

gethostname(name,20);

//获得主机名字03

hostent*p=gethostbyname(name);04

LPSTRlpAddr=p->h_addr_list[0];05

IN_ADDRinAddr;06

//从lpaddr所指内存复制4个字节到inAddr中07

memmove(&inAddr,lpAddr,4);08

//将网络字节序转化为主机字节序09

CStringipAddress=inet_ntoa(inAddr);

//获得主机IP地址当效劳器端监听到客户端的连接请求以后,可以调用函数accept()完成整个连接过程,并返回一个新的套节字。效劳器收发数据都是通过这个新套接字进行的。代码如下:01 SOCKETs1=::accept(s,NULL,NULL); //返回数据收发套接字02 //获取连接客户端的IP03 getpeername(s1,(SOCKADDR*)&add,(int*)sizeof(add));通过以上代码,用户可以清楚地看到本地IP地址和与效劳器连接的客户端IP等信息。函数accept()只能在效劳器端进行调用,因为该函数仅用于响应客户端连接请求。2.连接套接字在客户端中,套接字创立完成以后,用户需要通过该套接字向效劳器发出连接请求。通常,该操作由函数connect()进行,该函数返回–1,表示失败。否那么,表示成功。例如,客户端连接效劳器,效劳器端IP为,端口为80。代码如下:01 SOCKADDR_INaddr;02 addr.sin_family=AF_INET;03 addr.sin_port=htons(80);04 addr.sin_addr.S_un.S_addr=inet_addr("218.7.132.5");05 SOCKETs=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);06 if(!connect(s,(sockaddr*)&addr,sizeof(addr)))07 //向效劳器发送连接请求08 {09 ...10 }当客户端调用connect()函数向效劳器发出连接请求以后,效劳器会调用accept()函数对其进行响应,并返回数据收发套接字。例如,比较简单的效劳器响应客户端连接请求。代码如下:01 ... //省略局部代码02 if(INVALID_SOCKET=::accept(s,(sockaddr*)&addr,sizeof(sockaddr))03 //响应客户端的连接请求04 {05 MessageBox("客户端连接成功!"); //提示用户06 }07 else08 {09 MessageBox("客户端连接失败!");10 }在这里,如果运行该程序的机器没有连接网络,那么可以使用计算机的回环IP地址“”。7.2效劳器端程序在VC中,建立基于对话框的应用程序,命名为“网络通信Server”,设计如图7.1所示的软件界面。表7.1列出了效劳器界面控件ID及含义。图7.1效劳器端界面表7.1效劳器界面控件ID及含义控件关联的变量名及其类型如图7.2所示。ID含

义ID含

义IDS_STATUS显示客户端的IP地址IDC_SEND编辑将要发送的信息IDC_RECV接收客户端发来的信息IDC_SENDBTN发送信息IDC_STARTRUN开启服务器IDCANCEL断开连接图7.2关联变量名及其类型在类CServerDlg中定义两个成员变量,位置如下:7.2.1开启效劳器在按钮“开启效劳器”的响应函数OnStartrun()中要完成一系列的准备工作。〔1〕加载套接字库。函数WSAStartup()用来初始化Socket环境,原型如下:intWSAStartup(__in WORD wVersionRequested,__out LPWSADATA lpWSAData);参数wVersionRequested表示最高版本的调用者可以使用的套接字标准;参数lpWSAData指向了一个WSADATA结构,用来接收套接字实现的详细信息。函数调用成功时返回0。函数MAKEWORD()用来创立一个WORD值。〔2〕创立套接字。函数socket()调用失败时会返回 INVALID_SOCKET,以此作为判断依据。〔3〕获取效劳器端所在主机的IP地址。函数gethostname()用来获取主机名,原型如下:intgethostname(__out

char*

name,__in

int

namelen);参数name是指向用来接收主机名字符串的指针;参数namelen是这段内存的大小。函数调用成功返回0。函数gethostbyname()用来通过主机名获取记录主机IP的hostent结构,原型如下:structhostent*FARgethostbyname(__in

constchar*

name);参数name是指向记录主机名字符串的指针。函数返回一个指向hostent结构的指针,结构的定义如下:typedefstructhostent{charFAR*

h_name;charFARFAR**

h_aliases;short

h_addrtype;short

h_length;charFARFAR**

h_addr_list;}

HOSTENT,*PHOSTENT,FAR*LPHOSTENT;参数h_addr_list是指向记录主机IP地址的以NULL结尾的列表指针。其它参数不会用到,所以不做介绍。函数memmove()用来在指定的缓冲中拷贝指定的字节,函数原型如下:void*memmove(void*

dest,const

void*src,size_t

count);参数dest指向目标对象;参数src指向源对象;参数count指定拷贝的字节数。函数inet_ntoa()用来将网络字节序的地址字串转换为点分格式的主机字节序的地址字串。〔4〕绑定套接字与端口号。SOCKADDR_IN结构被套接字用来指向一个本地的或远程的用来建立网络连接的终点地址。原型如下:structsockaddr_in{short

sin_family;unsigned

short

sin_port;structin_addr

sin_addr;char

sin_zero[8];};参数sin_family表示地址簇,必须为AF_INET;参数sin_port是指定的端口号,网络字节序;参数sin_addr指向in_addr结构;参数sin_zero作为填充,使得sockaddr_in结构的大小和sockaddr结构的大小一样。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_long

S_addr;

}S_un;};参数S_addr是格式化为无符号长整形的主机IP地址。其它参数不会用到,不做介绍。函数inet_addr()用来将主机字节序的IP字串转换为网络字节序的IP字符串。〔5〕监听来自客户端的消息。函数listen()用来监听来自客户端的连接请求。SOMAXCONN为缓冲区能够保存的最大连接数。〔6〕设置异步套接字。函数WSAAsyncSelect()为套接字请求基于窗口消息的网络事件通知,原型如下:intWSAAsyncSelect(SOCKET

s,HWND

hWnd,unsignedint

wMsg,long

lEvent);参数s表示被请求事件通知的套接字描述符;参数hWnd表示当网络事件发生时接受消息的窗口句柄;参数wMsg表示当网络事件发生时接收到的消息;参数lEvent指定应用程序感兴趣的网络事件。可以用位操作符来构造多个事件。本章主要用到的消息为:FD_READ接收是否可读的通知;FD_ACCEPT接收与连接有关的通知。函数WSAAsyncSelect()调用成功时返回0。聚集以上各步骤,“开启效劳器”按钮的消息响应函数为:通过上面的代码,已经创立了效劳器套接字,并且将该套接字设置为异步模式。读者可以在其响应函数中处理FD_READ和FD_ACCEPT事件。在“网络通信ServerDlg.h”文件中添加自定义消息:#define

WM_SOCKET

WM_USER+100添加消息响应函数:在“网络通信ServerDlg.cpp”文件中添加消息映射:7.2.2响应连接与读取当客户端尝试与效劳器端建立连接时,效劳器端会收到FD_ACCEPT的事件通知,处理如下:函数accept()调用成功时会返回一个与客户端建立了通信连接的套接字,效劳器端与客户端的通信是通过此套接字来完成的。函数调用失败会返回INVALID_SOCKET。另外,响应代码还实现了显示客户端IP地址的功能,函数inet_ntoa()用来将网络字节序的IP地址字串转换为主机字节序的IP地址字串。当连接已经建立,效劳器可以通过处理FD_READ事件通知来接收来自客户端的信息。处理如下:对事件通知的消息处理实现了接收来自客户端的信息,并把信息显示在接收信息的文本框中。聚集以上各步骤,响应连接与读取的函数OnSocket()代码编写如下:7.2.3发送信息用户先在发送信息的文本框中编辑要发送的信息,然后单击“发送”按钮实现信息的发送。双击“发送”按钮,添加它的消息响应函数OnSendbtn()如下:函数send()通过与客户端建立的套接字发送信息,调用失败时会返回SOCKET_ERROR,消息响应函数的代码还实现了发送完消息后清空发送消息文本框的功能。7.2.4断开连接双击“断开连接”按钮,添加消息响应函数OnCancel(),代码如下:函数WSACleanup()会完成卸载Winsockdll的操作,调用成功时返回0。函数closesocket()会关闭套接字。7.3客户端程序在VC中,建立基于对话框的应用程序,命名为“网络通信Client”,设计如图7.3所示的软件界面。表7.2列出了客户端界面控件ID及含义。图7.3客户端程序界面表7.2客户端界面控件ID及含义控件关联的变量名及其类型如图7.4所示。ID含

义ID含

义IDC_IP需要输入的服务器端的IP地址IDC_SEND编辑将要发送的信息IDC_RECV接收客户端发来的信息IDC_SENDBTN发送信息IDC_CONNECT连接服务器IDCANCEL断开连接图7.4关联变量名及其类型在类CClientDlg中定义一个成员变量,位置如下:7.3.1连接效劳器双击“连接效劳器”按钮,添加消息响应函数OnConnect(),代码如下:消息响应函数中同样完成了加载Winsockdll、创立套接字和设置异步套接字的功能。用户首先要输入效劳器端的IP地址,然后单击“连接效劳器”按钮。其中connect()函数负责连接效劳器,返回0表示连接成功。代码中将套接字设置为异步模式,并选择对FD_READ事件进行处理。在“网络通信ClientDlg.h”文件中添加自定义消息:#define

WM_SOCKET

WM_USER+100添加消息响应函数:在“网络通信ClientDlg.cpp”文件中添加消息映射:7.3.2响应读取为自定义WM_SOCKET消息编写的响应函数为OnSocket(),代码如下:自定义消息的响应函数接收来自效劳器端发来的信息,并将接收到的消息显示在“数据接收”文本框中。函数recv()接收来自效劳器端的信息,原型为:intrecv(SOCKET s,char

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论