聊天室程序设计报告

实验5 掌握简单的网络通讯技术

实验6 掌握基于典型协议的的网络通讯技术

一 实验目的

1.熟悉Socket的通讯机制,了解网络程序的设计方法。

2. 熟悉典型协议的通讯机制,掌握基于它们的网络系统设计方法。如TCP、UDP。

二 实验环境

1.Windows7

2.Visual C++ 6.0

三 实验程序设计

1.实验原理 1.C/S模式

C/S模式是指一个服务器同时为多个客户端服务。并发性是C/S模式的的基础,正是由于并发性的支持,多个客户端能够获得同一种服务,而不必等待服务器完成对上一个请求的处理。

在C/S模式中,当请求到达服务器时,服务器将它交给一个控制线程,它能与已有的线程并发的执行。

在设计并发服务器时,一般服务器代码由两部分组成,第一部分代码负责监听并接收客户端的请求,还负责为客户端请求创建新的服务线程;另一部分代码负责处理单个客户机请求,如与客户机交换数据,提供具体服务。

下图所示为服务器创建多个线程来为多个客户机服务。

2.基于TCP的socket通信

服务器与客户端是通过套接字来进行通信的。

在基于TCP的网络通信程序中,首先服务器端通过socket()函数创建套接字,然后通过bind()函数来命名套接字,调用listen()函数开启服务器端的监听。接着执行accept()函数来接收客户的连接,服务器阻塞等待客户连接请求,直到有客户请求连接。

客户端创建套接字,接着通过connect()函数请求连接服务器,连接成功后,就可以与服务器进行通信了。

服务器与客户机通过send()各recv()调用来进行信息的发送和接收。只有当有信息可接收时,recv()才返回,否则将阻塞。

通信完后,服务器和客户机各自通过closesocket()函数来关闭套接字。 注:以上讲的是阻塞模式。

下图所示的是基于TCP的网络通信模式。

服务器端客户机端对于监听套接字创建套接字:SOCKET()对于连接套接字绑定套接字;BIND()创建套接字:SOCKET()启动监听:LISTEN()请求连接:CONNECT()请求连接(第一次握手)接受连接(第二次握手)接受客户的连接请求: ACCEPT()创建新的连接套接字如果没有已经到达的连接请求,就阻塞,等待客户的连接请求发送数据:WRITE() 请求服务器服务(第三次握手,同时发送数据)处理服务器的响应处理客户机的服务请求读取数据:READ()服务器发给客户机的响应读取数据:READ()发送数据:WRITE()关闭套接字:CLOSE()关闭套接字:CLOSE()关闭套接字:CLOSE()

2.系统设计

实验5要求在客户机和服务器传输图片和文件,如果是图片则显示,是文件则保存。这个实验中的客户机与服务器可以没有区别,即可以采用对等的模式,双方既可以是服务器也可以是客户机。因为没有要求一个对多个服务。

实现实验5中的要求最简单的可以选用基于UDP的对等模式,但是我们小组决定将实验5和实验6的功能集成在一个程序中,所以最后还是选用了基于TPC的网络通信。由客户机发送文件或图片到服务器,服务器检测到有文件可接收时,提示用户是否要接收来自己客户机的文件或图片,如果接收,则根据文件后缀名来判断文件类型,是图片就打开。

实验5中,难点在于怎么传递和接收文件,怎么判断一个文件是否传或者接收成功了。在传文件的过程中,我们先组装数据包,在数据包中,我们先传文件标识符,文件标识符是为了和聊天时的消息标识符以及其他自定义的标识符区分接收。然后再传文件名和文件的大小,最后是文件的内容。服务器接收时,依次解析出文件标识,文件名,文件大小,文件内容。

图片也是文件,通过后缀名可以识别是图片还是非图片。

实验6要求编写一个多人聊天室系统。聊天室程序是一个服务器接收来个多个客户端服务请求,这些请求是并发。采用C/S模式设计,服务器开启一个监听线程来接受来自一个客户端的连接请求,在收到请求后,在这个线程中为这个客户提供交互服务,同时开启另一个监听线程来监听其他客户的连接请求。这样就实现了服务器为多个不同的客户端提供并发服

务。

在设计C/S模式,当客户端很多时,或者并发很大时,阻塞模式是行不通的,因为可能造成多个客户机同时争夺服务器时,有的客户机不能及时得到服务而影响用户体验。我们小组曾尝试采用非阻塞模式,用了Select模型。但是由于以前没有网络编程经验、时间有限以及非阻塞模式很复杂,没有成功实现,最后还是采用了阻塞模式。不过,在实验中,还是没有出现性能问题。

怎么实现多人聊天室通信?首先客户机发送聊天信息到服务器,服务器接收到聊天信息后,在服务器的显示信息,并转发给所有的其他客户机。服务器可以发送公告信息给所有的客户机。当客户机下线时,该客户机发送下线标识消息到服务器,由服务器广播到其他客户机。

设计了一个在线客户列表,来同步时实显示在线的客户。实验中一个要点在于怎么实现同步显示在线客户。下面将在系统实现中讲述。

3.系统实现

这部分主要结合关键代码来讲解系统的实现思路及具体实现,详细代码见附录。我们小组实验5和实验6是在一个程序中实现的。 (1)服务器与客户端通信

服务器开启监听,这部分主要实现创建套接字、命名套接字、套接字监听,然后开启一个监听线程。

m_serversock=socket(AF_INET,SOCK_STREAM,0);//创建

ret=bind(m_serversock,(LPSOCKADDR)&addr,sizeof(addr));//绑定 ret=listen(m_serversock,10);//监听

AfxBeginThread(ListenThread,this); //开启一个监听线程

在ListenThread线程中,接收客户端请求,接收阻塞解除后再开启另一个监听线程来监听其他客户机的连接请求。

Clientsock[k].clientsock=accept(pDlg->m_serversock,(sockaddr *)&clientaddr,&clientlen);//接收客户端请求

AfxBeginThread(ListenThread,p); //开启另外一个监听线程,监听其他用户连接

接下来,接收信息标识符,并根据不同的消息标识符来判断采用相应的处理函数。char recvflag[3];

memset(recvflag,0,3);

int flagc=recv(clientsock[k].clientsock,recvflag,2,0); recvflag[2]='\\0'; CString strflag;

strflag.Format(\

自己定义的消息标识符有“QQ”表退出,“MM”表聊天信息,“FF”表文件,“CC”表连 PDlg->RecvMessage(clientsock[k].clientsock);//接收聊天消息 pDlg->RecvFile(clientsock[k].clientsock);//接收文件消息

客户端先创建套接字,然后主动连接服务器,开启一个接收线程来接收来自服务器的信息,在RecvFromServer线程中也是根据消息标识符来作不同的处理的。m_clientsocket=socket(AF_INET,SOCK_STREAM,0);//创建

联系客服:779662525#qq.com(#替换为@) 苏ICP备20003344号-4