12

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

 3 years ago
source link: https://www.cnblogs.com/Olive116/archive/2012/10/19/2730147.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
网络编程之即时通信程序(聊天室)------(一)通信流程简介及通信协议定制 - 星星之火116 - 博客园

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

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

2012101817524644.png
2012101817533085.png
2012101817542463.png

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

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

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

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

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

2012101818213010.png

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

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

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

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

listener.Start();

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

TcpClient tcpClient=new TcpClient();
int  port = 11615;
IPAddress ipAdd=IPAddress.Parse(“192.168.245.1”);
        tcpClient.Connect(ipAdd, port);

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

Socket clientSocket= listener.AcceptSocket();

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

NetworkStream stream = tcpClient.GetStream();

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

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

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

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

byte [] buffer=new byte[1024];
int length= stream.Read(buff,0,buff.Length);
string msg = Encoding.Default.GetString(buffer,0,length);

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

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

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

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

byte [] buffer=new byte[1024];
int length= stream.Read(buff,0,buff.Length);
string msg = 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的应用,以及相关的涉及的多线程的知识。

       好了,这一节就到这里了,希望能给大家带来些许帮助,同时也希望大家多多指点。                                                                                                                 


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK