局域网聊天程序设计方案.docx
- 文档编号:7350593
- 上传时间:2023-01-23
- 格式:DOCX
- 页数:25
- 大小:136.23KB
局域网聊天程序设计方案.docx
《局域网聊天程序设计方案.docx》由会员分享,可在线阅读,更多相关《局域网聊天程序设计方案.docx(25页珍藏版)》请在冰豆网上搜索。
局域网聊天程序设计方案
基于局域网聊天程序设计
摘 要:
本论文讨论了Windows环境下局域网聊天程序的设计思路和设计方法。
其中网络通信部分采用流行的TCP/IP协议。
程序采用典型的C/S(服务器/客户端)构架。
用socket编程设计网络通讯。
界面设计部分采用WindowsMFC框架。
数据库采用微软SQLServer。
本文最终设计了一个简易版本的聊天软件,包括登陆、退出、添加好友、消息收/发等功能。
关键词:
SocketsAPI,C/S构架,SQLServer。
RealizationofakindofLANchattool
Abstract:
ThisarticlediscusseshowtodesignanddevelopaLANchattingprograminWindowsenvironment.ThenetworkcommunicationpartdependsonthepopularTCP/IPprotocol.SoftwareisbasedonC/Sarchitecture.NetworkcommunicationisdevelopedwithSocket.UIisdesignedwithWindowsMFCframe.DatabaseisdesignedwithSQLserver.Thearticledescribesaconcisechartsoftwareversion,withthefunctionofloggingin/out,addingfriendtolist,sending/receivingmessageandsoon.
Keywords:
SocketsAPI,C/Sarchitecture,SQLServer
论文目录
第一章概述
即时通讯软件的出现正在逐渐改变人们的沟通与交际方式。
无论近在咫尺,还是远隔重洋,也只是在键盘和鼠标之间就可以解决问题。
即时通讯服务非常适合企业内部或企业和客户之间的交流。
而且将即时通讯服务和手机移动等服务结合,将更大地提高工作效率。
网络聊天程序.越来越影响着我们的网络生活。
习惯了通过类似ICQ、QQ、MSN之类的程序和天南海北的朋友聊天、发信息,不过所有聊天程序都需要Internet的支持,而无法在局域网内部“大显身手”,那么你是否想到过要让单位内部的员工,寝室周围的同学,不用上Internet就可以轻松体验到内网聊天的快乐呢?
有了这种想法,开发局域网聊天程序就有了必要性,让单位员工或寝室同学不出内网就能自由聊天!
本文主要研究的是一个具有高度实用性的聊天程序软件的设计原理,思路和过程。
通过该网络程序的编制和实践,对自己所学习的知识进行一次综合和提高,有更深层次的理解和掌握,在这过程中激发自己学习的潜力,提高软件开发的能力,加深对网络协议和windows环境下网络编程的理解和掌握。
第二章、WindowsSocket网络编程的研究
2.1TCP/IP体系结构
2.2.1TCP/IP简介
TCP/IP作为Internet的核心协议,通过近二十多年的发展已日渐成熟,并被广泛应用于局域网和广域网中,目前已成为事实上的国际标准。
TCP/IP协议集确立了Internet的技术基础。
TCP/IP协议主要作用于OSI网络参考模型中的网络层(第3层)、传输层(第4层)和应用层(第7层)。
数据链路层(第2层)的功能主要应用于其它协议如以太网(Ethernet)、ATM、帧中继(FrameRelay),以及多数供应商特定协议等。
TCP/IP充分支持所有通用第2层协议。
TCP/IP组中的应用程序通常直接运行于传输层协议TCP或UDP上面,并不需要表示层(第6层)和会话层(第5层)的支持。
2.2.2TCP/IP的特点
TCP/IP协议的核心部分是传输层协议(TCP、UDP),网络层协议(IP)和物理接口层,这三层通常是在操作系统内核中设计。
因此用户一般不涉及。
编程时,编程界面有两种形式:
一、是由内核心直接提供的系统调用;二、使用以库函数方式提供的各种函数。
前者为核内设计,后者为核外设计。
用户服务要通过核外的应用程序才能设计,所以要使用套接字(socket)来设计。
2.2基本套接字
下面给出几个基本的套接字,这些套接字的使用贯穿了网络编程的始末,主导了数据通信的过程。
这将在以后的篇幅中会给出更详细的使用说明。
1、创建套接字——socket()
功能:
使用前创建一个新的套接字
格式:
SOCKETPASCALFARsocket(intaf,inttype,intprocotol)。
参数:
af:
通信发生的区域
type:
要建立的套接字类型
procotol:
使用的特定协议
2、指定本地地址——bind()
功能:
将套接字地址与所创建的套接字号联系起来。
格式:
intPASCALFARbind(SOCKETs,conststructsockaddrFAR*name,intnamelen)。
参数:
s:
是由socket()调用返回的并且未作连接的套接字描述符(套接字号)。
其它:
没有错误,bind()返回0,否则SOCKET_ERROR
地址结构说明:
structsockaddr_in
{
shortsin_family。
//AF_INET
u_shortsin_port。
//16位端口号,网络字节顺序
structin_addrsin_addr。
//32位IP地址,网络字节顺序
charsin_zero[8]。
//保留
}
3、建立套接字连接——connect()和accept()
功能:
共同完成连接工作
格式:
intPASCALFARconnect(SOCKETs,conststructsockaddrFAR*name,intnamelen)。
SOCKETPASCALFARaccept(SOCKETs,structsockaddrFAR*name,intFAR*addrlen)。
参数:
同上
4、监听连接——listen()
功能:
用于面向连接服务器,表明它愿意接收连接。
格式:
intPASCALFARlisten(SOCKETs,intbacklog)。
5、数据传输——send()与recv()
功能:
数据的发送与接收
格式:
intPASCALFARsend(SOCKETs,constcharFAR*buf,intlen,intflags)。
intPASCALFARrecv(SOCKETs,constcharFAR*buf,intlen,intflags)。
参数:
buf:
指向存有传输数据的缓冲区的指针。
6、多路复用——select()
功能:
用来检测一个或多个套接字状态。
格式:
intPASCALFARselect(intnfds,fd_setFAR*readfds,fd_setFAR*writefds,
fd_setFAR*exceptfds,conststructtimevalFAR*timeout)。
参数:
readfds:
指向要做读检测的指针
writefds:
指向要做写检测的指针
exceptfds:
指向要检测是否出错的指针
timeout:
最大等待时间
7、关闭套接字——closesocket()
功能:
关闭套接字s
格式:
BOOLPASCALFARclosesocket(SOCKETs)。
2.3客户机/服务器模式
在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Servermodel)。
该模式的建立基于以下两点:
1、非对等作用;2、通信完全是异步的。
客户机/服务器模式在操作过程中采取的是主动请示方式:
首先服务器方要先启动,并根据请示提供相应服务,过程如下所示:
1、打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求。
2、等待客户请求到达该端口。
3、接收到重复服务请求,处理该请求并发送应答信号。
4、返回第二步,等待另一客户请求
5、关闭服务器。
客户方:
1、打开一通信通道,并连接到服务器所在主机的特定端口。
2、向服务器发送服务请求报文,等待并接收应答;继续提出请求……
3、请求结束后关闭通信通道并终止。
2.4WINDOWSSOCKETS程序设计
2.4.1WINDOWSSOCKETSAPI简介
VC++对网络编程的支持有socket支持,WinInet支持,MAPI和ISAPI支持等。
其中,WindowsSocketsAPI是TCP/IP网络环境里,也是Internet上进行开发最为通用的API。
最早美国加州大学Berkeley分校在UNIX下为TCP/IP协议开发了一个API,这个API就是著名的BerkeleySocket接口(套接字)。
在桌面操作系统进入Windows时代后,仍然继承了Socket方法。
在TCP/IP网络通信环境下,Socket数据传输是特殊的I/O,它也相当于文件描述符,具有一个类似于打开文件的函数调用-socket()。
可以这样理解:
Socket实际上是一个通信端点,通过它,用户的Socket程序可以通过网络和其他的Socket应用程序通信。
Socket存在于一个"通信域"(为描述一般的线程如何通过Socket进行通信而引入的抽象概念)里,并且与另一个域的Socket交换数据。
Socket有三类。
第是SOCK_STREAM(流式),提供面向连接的可靠的通信服务,比如telnet,http。
第二种是SOCK_DGRAM(数据报),提供无连接不可靠的通信,比如UDP。
第三种是SOCK_RAW(原始),主要用于协议的开发和测试,支持通信底层操作,比如对IP和ICMP的直接访问。
2.4.1WINDOWSSOCKETS机制
1、异步选择机制:
WINDOWSSOCKETS的异步选择函数提供了消息机制的网络事件选择,当使用它登记网络事件发生时,应用程序相应窗口函数将收到一个消息,消息中指示了发生的网络事件,以及与事件相关的一些信息。
WINDOWSSOCKETS提供了一个异步选择函数WSAAsyncSelect(),用它来注册应用程序感兴趣的网络事件,当这些事件发生时,应用程序相应的窗口函数将收到一个消息。
函数结构如下:
intPASCALFARWSAAsyncSelect(SOCKETs,HWNDhWnd,unsignedintwMsg,long
lEvent)。
参数说明:
hWnd:
窗口句柄
wMsg:
需要发送的消息
lEvent:
事件(以下为事件的内容)
值:
含义:
FD_READ期望在套接字上收到数据(即读准备好)时接到通知
FD_WRITE期望在套接字上可发送数据(即写准备好)时接到通知
FD_OOB期望在套接字上有带外数据到达时接到通知
FD_ACCEPT期望在套接字上有外来连接时接到通知
FD_CONNECT期望在套接字连接建立完成时接到通知
FD_CLOSE期望在套接字关闭时接到通知
例如:
我们要在套接字读准备好或写准备好时接到通知,语句如下:
rc=WSAAsyncSelect(s,hWnd,wMsg,FD_READ|FD_WRITE)。
如果我们需要注销对套接字网络事件的消息发送,只要将lEvent设置为0。
2、异步请求函数
在BerkeleySockets中请求服务是阻塞的,WINDOWSSICKETS除了支持这一类函数外,还增加了相应的异步请求函数(WSAAsyncGetXByY()。
)。
3、阻塞处理方法
WINDOWSSOCKETS为了设计当一个应用程序的套接字调用处于阻塞时,能够放弃CPU让其它应用程序运行,它在调用处于阻塞时便进入一个叫“HOOK”的例程,此例程负责接收和分配WINDOWS消息,使得其它应用程序仍然能够接收到自己的消息并取得控制权。
WINDOWS是非抢先的多任务环境,即若一个程序不主动放弃其控制权,别的程序就不能执行。
因此在设计WINDOWSSOCKETS程序时,尽管系统支持阻塞操作,但还是反对程序员使用该操作。
但由于SUN公司下的BerkeleySockets的套接字默认操作是阻塞的,WINDOWS作为移植的SOCKETS也不可避免对这个操作支持。
在WINDOWSSOCKETS设计中,对于不能立即完成的阻塞操作做如下处理:
DLL初始化→循环操作。
在循环中,它发送任何WINDOWS消息,并检查这个WINDOWSSOCKETS调用是否完成,在必要时,它可以放弃CPU让其它应用程序执行(当然使用超线程的CPU就不会有这个麻烦了)。
我们可以调用WSACancelBlockingCall()函数取消此阻塞操作。
在WINDOWSSOCKETS中,有一个默认的阻塞处理例程BlockingHook()简单地获取并发送WINDOWS消息。
如果要对复杂程序进行处理,WINDOWSSOCKETS中还有WSASetBlockingHook()提供用户安装自己的阻塞处理例程能力;与该函数相对应的则是SWAUnhookBlockingHook(),它用于删除先前安装的任何阻塞处理例程,并重新安装默认的处理例程。
请注意,设计自己的阻塞处理例程时,除了函数WSACancelBlockingHook()之外,它不能使用其它的WINDOWSSOCKETSAPI函数。
在处理例程中调用WSACancelBlockingHook()函数将取消处于阻塞的操作,它将结束阻塞循环。
4、出错处理
WINDOWSSOCKETS为了和以后多线程环境(WINDOWS/UNIX)兼容,它提供了两个出错处理函数来获取和设置当前线程的最近错误号。
(WSAGetLastEror()和WSASetLastError())
5、启动与终止
使用函数WSAStartup()和WSACleanup()启动和终止套接字。
第三章、网络通信模块分析
3.1网络通信程序设计过程
在调用了Windowssockets的启动函数WSACleanup()之后才能进行其他的Socket系统调用,但启动函数WSAStartup()是为了建立与WindowsSocketsDLL的连接,因此在VC++6.0所建立工程的工程设置中的连接的库模块必须进行设置,在其中的link栏内的对象/库模块中加入“Ws2_32.lib”,才能真正建立建立与WindowsSocketsDLL的连接。
其他的Socket系统调用包括创建Socket、将创建的Socket与本地端口绑定、建立Socket连接服务器、监听是否有连接、请求数据的可控缓冲发送和可控缓冲接收,到最后关闭Socket。
具体流程图如1所示。
首先在服务器方,利用socket()函数建立流式套接字,返回套接字号s,接着利用bind()函数将套接字s与本地地址绑定,紧接着利用listen(0函数通知TCP,监听客户方,服务器准备接收连接,没有连接的话,服务器方通过closesocket()关闭套接字s,服务结束。
有连接的话,在客户方,通过socket()函数建立流式套接字s,此时在服务器方,建立连接,通过accept()返回,得到新的套接字ns,客户方通过connect()将套接字s与远程地址连接,此时服务器方/客户方在ns/s上读/写数据,直到交换完成。
交换完成后,服务器方/客户方关闭套接字ns/s,最后服务器方通过closesocket()关闭最初套接字s,服务结束。
具体设计过程如图1所示,具体设计代码将会在下面介绍:
图1面向连接的套接字的系统调用流程图
3.2网络通信程序设计核心代码分析
3.2.1通信设计代码分析
先分析服务器端。
首先定义初始化网络函数,也就是WINDOWSSOCKETS的启动
在所有WINDOWSSOCKETS函数中,只有启动函数WSAStartup()和终止函数WSACleanup()是必须使用的。
启动函数必须是第一个使用的函数,而且它允许指定WINDOWSSOCKETSAPI的版本,并获得SOCKETS的特定的一些技术细节。
本结构如下:
intPASCALFARWSAStartup(WORDwVersionRequested,LPWSADATAlpWSAData)。
其中wVersionRequested保证SOCKETS可正常运行的DLL版本,如果不支持,则返回错误信息。
设计代码如下,主要是进行WSAStartup()函数的调用
WORDwVersionRequested。
//定义版本信息变量
WSADATAwsaData。
//定义数据信息变量
interr。
//定义错误号变量
wVersionRequested=MAKEWORD(1,1)。
//给版本信息赋值
err=WSAStartup(wVersionRequested,&wsaData)。
//给错误信息赋值
if(err!
=0)
{
return。
//告诉用户找不到合适的版本
}
//确认WINDOWSSOCKETSDLL支持1.1版本
//DLL版本可以高于1.1
//系统返回的版本号始终是最低要求的1.1,即应用程序与DLL中可支持的最低版本号
if(LOBYTE(wsaData.wVersion)!
=1||HIBYTE(wsaData.wVersion)!
=1)
{
WSACleanup()。
//告诉用户找不到合适的版本
return。
}
//WINDOWSSOCKETSDLL被进程接受,可以进入下一步操作
既然启动了到最后就需要调用WSACleanup()函数来终止,关闭函数使用时,任何打开并已连接的SOCK_STREAM套接字被复位,但那些已由closesocket()函数关闭的但仍有未发送数据的套接字不受影响,未发送的数据仍将被发送。
程序运行时可能会多次调用WSAStartuo()函数,但必须保证每次调用时的wVersionRequested的值是相同的。
接着是创建服务器端套接字,主要代码如下:
SOCKETServerSock。
//服务器端Socket
ServerSock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)。
if(ServerSock==INVALID_SOCKET)
{
MessageBox("创建套接字失败!
")。
closesocket(ServerSock)。
WSACleanup()。
returnFALSE。
}
套接字创建好之后就是与本地地址绑定:
sockaddr_inlocaladdr。
localaddr.sin_family=AF_INET。
localaddr.sin_port=htons(8888)。
file:
//端口号不要与其他应用程序冲突
localaddr.sin_addr.s_addr=0。
if(bind(ServerSock,(structsockaddr*)&localaddr,sizeof(sockaddr))
==SOCKET_ERROR)
{
MessageBox("绑定地址失败!
")。
closesocket(ServerSock)。
WSACleanup()。
returnFALSE。
}
接下来就是对SOCKET的设置,本程序使用的数据传输模式是异步非阻塞模式,设置好之后就是监听客户端信息,主要代码如下
if(WSAAsyncSelect(ServerSock,m_hWnd,NETWORK_EVENT,
FD_ACCEPT|FD_CLOSE|FD_READ|FD_WRITE)==SOCKET_ERROR)
{
MessageBox("注册网络异步事件失败!
")。
WSACleanup()。
returnFALSE。
}
listen(ServerSock,5)。
//设置侦听模式
returnTRUE。
}
其中m_hWnd为应用程序的主对话框或主窗口的句柄。
这就要说到网络异步函数的回调函数,主要代码内容如下:
OnNetEvent(WPARAMwParam,LPARAMlParam){
//调用WinsockAPI函数,得到网络事件类型
intiEvent=WSAGETSELECTEVENT(lParam)。
//调用WinsockAPI函数,得到发生此事件的客户端套接字
SOCKETCurSock=(SOCKET)wParam。
switch(iEvent)
{
caseFD_ACCEPT:
//客户端连接请求事件
OnAccept(CurSock)。
break。
caseFD_CLOSE:
//客户端断开事件:
OnClose(CurSock)。
break。
caseFD_READ:
//网络数据包到达事件
OnReceive(CurSock)。
break。
caseFD_WRITE:
//发送网络数据事件
OnSend(CurSock)。
break。
default:
break。
}}
另外,发生在相应Socket上的各种网络异步事件的处理函数,其中OnAccept传进来的参数是服务器端创建的套接字,OnClose()、OnReceive()和OnSend()传进来的参数均是服务器端在接受客户端连接时新创建的用与此客户端通信的Socket。
定义OnAccept()函数来接受连接请求,并保存与发起连接请求的客户端进行通信Socket,为新的socket注册异步事件。
定义OnSend()函数来给客户端发数据时做相关预处理。
定义OnReceive()函数来读出网络缓冲区中的数据包。
定义OnClose()函数来结束与相应的客户端的通信,释放相应资源。
接下来讲讲客户端方。
首先初始化网络部分,带不需要将套接字设置为监听模式。
注册异步事件时,没有FD_ACCEPT,但增加了FD_CONNECT事件,因此没有OnAccept()函数,但增加了OnConnect()函数。
向服务器发出连接请求时,使用connect()函数,连接成功后,会响应到OnConnect()函数中。
下面是OnConnect()函数的定义,传进来的参数是客户端Socket和服务器端发回来的连接是否成功的标志。
voidCXFQQClientDlg:
:
OnConnect(SOCKETCurSock,interror)
{
if(0==error)
{
if(CurSock==ClntSock)
MessageBox("连接服务器成功!
")。
}
}
另外定义OnReceive()函数来处理网络数据到达事件。
定义OnSend()函数来处理发送网络数据事件。
定义OnClose()函数来处理服务器的关闭事件。
3.2.2数据传输代码分析
在服务器方用
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 局域网 聊天 程序设计 方案