您的位置:首页 > 理论基础 > 计算机网络

网络编程之即时通信程序(聊天室)------(一)通信流程简介及通信协议定制

2012-10-19 08:33 513 查看
在开始讲之前,我想先跟大家描述一下,这个所谓的通信程序具体是一个什么样的东西。该通信程序类似一个弱版本的qq,登录时需要进行注册,登录成功后,可以实现即时的通信,群聊,私聊,同时还可传文件。先上个图

服务端:客户端登录:客户端主界面:







所谓的即时的通信程序,也就是利用TCP和UDP的传输协议,进行信息、文件的传输。那什么是TCP,什么是UDP呢?

TCP是TransmissionControlProtocol(传输控制协议)的简称,是TCP/IP体系中面向连接的运输层协议,在网络中提供全双工的和可靠的服务。TCP协议的主要特点是:基于连接的协议,数据传输比较稳定,且可以保证数据按顺序的准时达。

UDP是UserDatagramProtocol(用户数据报协议)的简称,是OSI参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。UDP协议的主要特点是:基于无连接协议,数据传送迅速,反应快,同时缺点也很明显,就是数据传输不稳定,不能保证数据到达的顺序,可能会有数据的缺失。

我们所熟悉的QQ就是一种基于TCP和UDP两种协议结合的一种即时通信程序,在我们进行会话、聊天的时候,采用UDP协议,通过服务器中转方式。大家都知道,UDP协议是不可靠协议,它只管发送,不管对方是否收到的,但它的传输很高效。但是,作为聊天软件,怎么可以采用这样的不可靠方式来传输消息呢?于是,腾讯采用了上层协议来保证可靠传输:如果客户端使用UDP协议发出消息后,服务器收到该包,需要使用UDP协议发回一个应答包。如此来保证消息可以无遗漏传输。之所以会发生在客户端明明看到“消息发送失败”但对方又收到了这个消息的情况,就是因为客户端发出的消息服务器已经收到并转发成功,但客户端由于网络原因没有收到服务器的应答包引起的。在我们进行文件传输的时候使用的是基于TCP的数据传输协议,因为要保证传输数据的顺序到达,同时还要保证不能有数据的丢失。

在我们的.NET平台下如果想要实现即时的通信就需要借助于Socket网络编程,Socket(网络套接字)是网络通信的基本构件,它是可以被命名和寻址的通信端口,使用中,每个Socket都有对应的类型和一个与之相关的进程。在开始介绍Socket创建即时通信之前我们需要先了解下使用TCP进行即时通信的操作流程:



下边我会结合这个流程图,一步一步跟大家讲通信的具体流程。

1、创建服务端套接字,监听本机的IP和一个特定的端口,把本机作为服务端。(下面的只是一个简单的演示实例)

intport=11615;//监听端口,最好设置的大一些,避免和一些特定的端口冲突 IPAddressipAdd=IPAddress.Parse(“192.168.245.1”);//监听IP,我们通过Dns.GetByHostName().Arrylist[],动态获得本机的IP,这里仅是示例。 TcpListenerlistener=newTcpListener(ipAdd,port);//创建监听对象

2、监听服务器端口,等待客户端连接请求

listener.Start();

3、创建客户端的套接字,并向远程服务端发送连接请求

TcpClienttcpClient=newTcpClient();
intport=11615;
IPAddressipAdd=IPAddress.Parse(“192.168.245.1”);
tcpClient.Connect(ipAdd,port);




4、服务端确认与客户端的连接,并创建与该客户端对应的Socket对象

SocketclientSocket=listener.AcceptSocket();

5、客户端获取与服务器通信的流通道

NetworkStreamstream=tcpClient.GetStream();

6、客户端通过流通道与服务器端进行数据传输

6.1、客户端向服务器端发送数

stringhello=“HelloWorld!”;
byte[]buffer=Encoding.Default.GetBytes(hello);
stream.Write(buffer,0,buffer.Length);

  6.2、客户端接收从服务器端发来的数据

byte[]buffer=newbyte[1024];
intlength=stream.Read(buff,0,buff.Length);
stringmsg=Encoding.Default.GetString(buffer,0,length);

7、服务端接受客户端请求

7.1、服务端向客户端发送数据

stringhello=“HelloWorld!”;
byte[]buffer=Encoding.Default.GetBytes(hello);
stream.Write(buffer,0,buffer.Length);


7.2、服务端接收从客户器端发来的数据

byte[]buffer=newbyte[1024];
intlength=stream.Read(buff,0,buff.Length);
stringmsg=Encoding.Default.GetString(buffer,0,length);


8、服务端断开与客户端的连接

clientSocket.Close();

9、客户端断开与服务端的连接

tcpClient.Close();

10、服务端关闭服务套接字

tcpClient.Close();

大体的通信流程就是这样子,但是到具体的实际应用中还有不同,因为我们要涉及到多个客户端之间的交互,而服务端只是相当于一个中间的媒介,接收客户端传递的消息,并将消息转发给另一个客户端,如果有多个客户端,同时进行通信,而这个时候就需要用到多线程进行通信的管理和控制。

具体的流程如下:

首先,我们在需要服务端创建一个TCPLister对象,启用一个线程,专门负责监听客户端的请求。

其次,只要有一个客户端进行请求,则TCPLister对象会马上创建一个专门负责通信的Socket与客户端请求的套接字,

同时再启用一个新的线程专门负责与客户端进行通信。

在客户端,我们只需要创建一个TCPClient对象,启用一个新的线程来专门的负责信息的接受即可。

在具体的通过过程中,我们还需要定制一些列的消息通信协议,在消息内部用“|”管道符将其内容进行分割,通过对协议的解析我们可以对不同的消息做不同的处理。在本应用才程序中,具体的通信协议如下:

在服务端接收协议如下:

命令格式

接收到客户端发送的通信流的字节数组中的首字节Msg[0]

说明

1、如果Msg[0]则说明发送的是文件,则遍历在线用户列表,像用户在线用户逐一发送该字节数组

2、如果Msg[0]!=0,则说明发送过来的信息字符串,则直接进行Encoding将字节数组转换为字符串,并对字符串进行如下的分析,根据不同的分析结果执行不同的命令。

ON|发送者的用户名|

1、该命令在客户端与服务器端建立连接后由客户端自动发送

2、服务器端收到该命令后,将“用户名”添加到在线用户列表并向所有在线用户发送消息“***上线啦!"

Off|发送者的用户名|

1、该命令是在用户上线、或者离开时执行的,用于向客户端发送在线人员名单,客户端接受到该信息后就会对在线列表进行更新。

MSG|接收者姓名|发送者姓名|发送内容|

MSGALL|发送者的用户名|发送内容|

1、该命令是用户点击发送消息按钮时,发送的信息,前提是用户必须选定要发送的对象

2、服务端收到该消息后,对消息进行解析,从中取得接受者用户名,并从在线列表中取得相应的通讯Socket,将“发送者用户名说“发送内容“这样格式的消息发送回客户端

3、如果是MSGALL,则为群发消息,服务器端收到该命令后,将遍历在线用户列表的用户,并逐一向在线用户发送”发送者的用户名说‘发送内容’”这样的信息发送给所有的在线用户

在客户端接收协议如下:

命令格式

说明

接受服务端发送的通信流字节数组中的首字节Msg[0]

如果Msg[0]==0则说明服务端发送的是文件,直接新建文件流从接收到的字节数组中的第二个字节开始读取,读取长度为字节数组长度减一个字节,并在本地保存文件。

如果Msg[0]!=0则说明服务端发送的是消息字符串,然后再根据下面的命令格式进行解析,进而做出不同的操作

OnLine|刚登录的用户名|

客户端收到该命令后,在聊天串口中看到“****”上线了的通知!

Off|用户1、用户2、用户3、|

该命令是在服务器端收到客户端发来的Off和On命令,回发给客户端的命令,然后客户端解析命令,更新在线人员列表。

以上这些就是该即时通信程序的通信格式,在下一节中,我会带领大家一步一步的构建该即时通信程序的服务端,在构建的过程中会逐步向大家演示TCPLister的应用,以及相关的涉及的多线程的知识。

好了,这一节就到这里了,希望能给大家带来些许帮助,同时也希望大家多多指点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐