首页 > 范文大全 > 正文

基于Linux的网络聊天系统设计

开篇:润墨网以专业的文秘视角,为您筛选了一篇基于Linux的网络聊天系统设计范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

摘 要: 为了让Linux系统用户得到更多网络聊天的支持,基于套接字编程方法设计了一种应用在linux网络聊天系统,它具有群聊、私聊、查询、信息加密等功能,并在Fedora 10系统上做了相应验证性实验。实验结果表明其完全达到了设计的预设要求,具有较强的实用性。

关键词: 套接字; TCP; 客户端; 服务端

中图分类号: TN711?34; TP311.1 文献标识码: A 文章编号: 1004?373X(2013)03?0051?04

随着互联网的发展,人与人之间的交流方式变得多样化。网络聊天就是其中一种新起的交流方式,其不分地域,具有实时性,只要有网络和聊天系统就可以进行交流。作为开源的操作系统,Linux自然拥有不少的用户,特别在服务器的应用上更是广泛。而如今大多数的网络聊天系统都是针对Windows系统开发的,针对Linux系统的相对比较少。因此本文设计了一种基于套接字编程方法针对Linux的网络聊天系统,其具有最基本的聊天功能:群聊和私聊,除此之外,本系统还添加了查询、信息加密、内容发送时间、服务器显示信息等功能。

1 系统原理

1.1 套接字的概述

套接字(Socket)是网络通信的基础,是支持TCP/IP协议的网络通信的基本操作单元[1]。套接字可以被认为是网络通信连接中的端点,接入局域网中的每台主机都是用套接字来标识,有了套接字,才能保证发送的数据能传送到正确的主机上。

在网络通信中,主要是通过IP地址、传输协议(TCP/UDP)、端口三个参数来区别网络中不同主机之间的通信[2]。Linux中的一切都是文件,内核是利用文件描述符(file descriptor)来访问文件,在网络操作中也是通过文件描述符来进行发送和接收数据的[3]。套接字就是结合以上三个参数,与一个文件描述符绑定得到的,从而主机就可以通过创建套接字与其他主机进行信息的传递。

1.2 TCP/IP协议中套接字的类型

在TCP/IP协议中,有3种常用的套接字类型[2,4]:流套接字(SOCK_STREAM)、数据包套接字(SOCK_DGRAM)、原始套接字(SOCK_RAW)。字节流套接字使用了传输控制协议,即TCP(The Transmission Control Protocol)协议,因此其用于提供面向连接的、可靠的数据传输服务,该服务可以实现顺序、无差错、不重复的流传输;而数据包套接字使用的是用户数据报协议,即UDP(User Datagram Protocol)协议,该协议是一种无连接的、不可靠的传输层协议,因此其提供的传输服务是不能保证数据传输的可靠性,在传输过程中有可能出现数据丢失、数据重复以及不能顺序接收数据的情况,其只适合于可靠性较高的局域网;原始套接字允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备。

本系统要实现聊天系统的功能,就涉及到字符串数据的传输,数据的顺序及可靠性要得到充分保证,因此本系统决定使用的是字节流套接字。

1.3 TCP协议

TCP是一种面向连接的、可靠的传输层协议[5]。TCP协议在网络层IP协议的基础上,向用户进程提供可靠性、全双工的数据流传输[6]。TCP在进行数据传递之前,必须先建立传输连接;在数据传输完毕后,需要释放传输连接。

1.3.1 TCP连接的建立

TCP协议建立连接必须经过三次握手[7](见图1)。在握手之前,服务器必须一直处于监听的状态,等待客户的连接请求。第一次握手:客户向服务器发送SYN包,并等待服务器的响应,SYN是同步序列编号;第二次握手:服务器必须对客户发送过来的SYN包进行确认,同时向客户发送一个SYN包,即此时发送给客户的是SYN包+ACK包;第三次握手:客户收到服务器发送过来的SYN包和ACK包后,向服务器发送对SYN包确认的ACK包。这样三次握手完成,传输连接就此建立,之后就可以在连接上进行数据的传送。

1.3.2 TCP连接的释放

当数据传输结束后,TCP会通过四次握手[7](见图2)来终止传输连接。第一次握手:客户通过发送FIN包向服务器提出释放连接的请求,并等待服务器响应的确认;第二次握手:服务器收到来自客户端的FIN包后会向其发送一个ACK包,表示同意释放连接;第三次握手:服务器向客户发送FIN包来表示其要关闭连接;第四次握手:客户向服务器发送ACK包来确认收到服务器送过来的FIN包,至此,TCP连接彻底终止。

1.4 客户/服务器模型

在客户/服务器模型中,多个相互通信的主机都作为客户端,与服务器进行连接,并以服务器作为数据中转来进行客户间的信息传递[8]。从另一个角度来看,多个客户端之间的通信实际上就是服务器与客户端之间端对端的通信。本系统设计的是多用户聊天系统,所用到的就是客户/服务器模型,因此需要分别用C语言编写服务端程序与客户端程序。服务端与客户端利用TCP连接进行通信的程序流程图[9?10]如图3所示,其中方框里的是套接字函数。

2 系统设计的具体实现

2.1 常用套接字函数的介绍

(1)socket函数:原型是int socket(int family,int type,int protocol),该函数功能是指明了协议族与套接字类型,其中本系统设置其参数family=AF_INET,type=SOCK_STREAM,protocol=0,表明使用IPv4协议,字节流套接字。该函数在成功时返回一个小的非负整数值;出错时,返回-1。

(2)connect函数:原型是int connect(int sockfd,SA *serv_addr,int addrlen),该函数功能是客户用来建立与TCP服务器的连接,其中参数sockfd是由socket函数返回的套接字文件描述符,第二、三个参数分别是一个指向套接字地址结构的指针和该结构的大小,serv_addr是保存目的地址端口和IP地址,其成功时返回值为0,出错时返回-1。

(3)bind函数:原型是int bind (int sockfd,const SA*my_addr,int addrlen),该函数功能是给套接字分配一个本地协议地址,其中sockfd也是由socket函数返回的套接字文件描述符,my_addr是指向套接字地址结构的指针,也即保存IP地址和端口信息,addrlen为该数据结构的大小。其成功时返回值为0,出错时返回-1。该函数主要用在服务端。

(4)linsten函数:原型是int listen(int sockfd,int backlog),其功能是把一个未连接的套接字转换成一个被动套接字,指示内核要接受该套接字的连接请求,其中sockfd是socket函数成功调用返回的套接字文件描述符,backlog指明该套接字中队排队的最大连接个数。成功时返回0,失败时返回-1。该函数仅由服务器调用,并且一般都是在socket函数跟bind函数后调用。

(5)accept函数:原型是int accept(int sockfd,SA*

cliaddr, int* addrlen),该函数功能是在已完成队列连接队列队头返回下一个已完成连接,如果已完成队列为空,则进程会处于阻塞状态。参数sockfd跟其上面提到的一样,是返回的套接字文件描述符,而cliaddr,addrlen分别是函数成功调用返回的客户进程协议地址和地址的大小,除以上返回外,该函数还会返回新套接字文件描述符(也就是已连接的套接字),失败时返回-1。该函数也是由TCP服务器调用。

(6)close函数:原型是int close(int sockfd),该函数功能是关闭套接字,并终止TCP连接。参数sockfd是要关闭的套接字,成功时返回0,失败时返回-1。

(7)输入输出函数:由于本系统是主机跟主机之间的文字信息交互的平台,涉及到客户端和服务端输入输出的操作,因此需要使用到输入输出函数。

套接字的输入函数:readline函数从套接字读入一串字符,并将该字符串存入到字符数组中。函数成功时返回输入字符串的长度,错误时返回-1。

套接字的输出函数:writen函数把字符数组中的字符串写入到套接字中,成功时返回写入字符串的长度,错误时返回-1。

键盘输入函数:fgets函数接收用户从键盘输入的字符串,并将该字符串存入字符数组中。

终端输出函数:fputs函数将字符串输出到终端,显示字符串。

(8)select函数:使用输入输出函数会使客户出现阻塞于标准输入或套接字输入的情况,也就是说程序会等待用户键盘输入或者等待套接字的输入[10]。当服务器进程终止后,客户端仍阻塞于标准输入,此时客户再次输入字符串时才会发现服务器已经终止,但是服务器并没有告知客户端TCP服务器已关闭了连接,因此客户端不能单纯阻塞于标准输入和套接字某个特定源的输入,而应该阻塞于其中任何一个源的输入。为了解决这个问题,就引入了select函数。select函数会等待多个事件中的任何一个发生,当某个事件或多个事件发生或经历一定时间时,它会告知内核进行处理。select函数可以设置四种感兴趣的事件集,分别是读、写或异常条件,以及等待多长时间。本系统调用select函数,主要用于检查可读性的描述字集,也就是当套接字或标准输入可读时,才会唤醒内核去处理。

(9)shutdown函数:输入的文件结束符并不意味着已完成了从套接字的读入,可能仍有请求在去往服务器的路上或是在去往客户的路上仍有应答,因此就需要一种方法来关闭TCP连接的一半,这就是由shutdown函数来完成[10]。shutdown函数可以终止数据传送的两个方向:读或写,或其中任一方向:读或写。本系统主要在客户端使用到shutdown函数,当收到服务器要关闭连接的信息时,就用shutdown函数关闭连接的写方向,从而避免客户继续发送信息,同时由于保留了连接的读方向,客户仍能收到在传输路上的信息。

2.2 各功能的具体实现思想

本系统主要的工作是编写客户端和服务端程序,其中服务器是数据中转的主要承担者,其工作量比较大,因此系统的关键在于服务端程序的设计。客户端程序的主要任务是完成用户、套接字的输入输出。而服务端程序不但要完成套接字的输入输出,而且要完成实现各功能的设计。

2.2.1 群聊功能

本系统是设计聊天系统,群聊是其最基本的功能。在服务器中,每个与服务端连接的客户都用不同的套接字来标识,而且每个客户都会有自定义的用户名。群聊是采取广播的形式,当某个客户要发送信息给大家时,服务器调用time函数来获得当前时间,并将此时间与原信息、信息来源者的用户名结合在一起,一并发送给已连接上的客户,这样就完成了一次信息的广播发送。

2.2.2 私聊功能

私聊功能是客户与客户之间单对单的聊天,本系统主要用“&目标用户名”的指令来表明私聊,其中目标用户名就是想要聊天的对象用户名,在指令后加上要发送的内容就可以向对方传送信息。服务器是用套接字来标识不同客户的,而且套接字是惟一的,只要找到与用户名相对应的套接字就能准确地将内容发送到目的客户。服务端程序就是先从指令中提取用户名,再根据用户名找到相应的套接字,最后就将内容发给对应的套接字。

2.2.3 加密功能

为了信息的保密性,本系统对内容的传送都进行了加密的操作。客户端、服务端在向套接字发送数据时,都会将数据进行加密,所谓的加密就是将数据倒序或者加上某个数之类的操作。而在套接字接收到数据时要先对数据进行解密,后才进行后续的工作。解密是加密的逆过程,两者必须要对应才能使数据复原正确。由于客户端跟服务端都有对套接字进行输入输出的操作,因此两者的程序中都包含了对数据加密跟解密的程序块。

2.2.4 查询在线用户功能

当客户使用当输入指令“#”,就可以查询当前在线用户。要实现此功能是较为简单的,只要在服务器中判断是否“#”指令,如果是的话,服务器通过套接字来查询已连接的用户名,并将各用户名结合到同一条信息上,之后发送给输入指令的客户。

3 实验效果

为了测试本系统是否达到设计要求,在fedora 10系统上做了实验。该实验需要打开四个控制终端,一个运行服务端程序,三个运行客户端程序。在终端上输入./tcpserver就能启动服务程序,输入./tcpclient 127.0.0.1启动客户程序,其中127.0.0.1是回送地址,指本地机,一般用来测试使用。