首先感谢以上知友提供的帮助~没有他们的工作不可能会有我的成果~侵删
我的项目在第一篇链接的基础上加入了文件传输、语音传输的功能,也支持文件的查看和下载。
项目背景
一、相关工作
1. 了解网络编程,阅读有关socket编程实例和应用的网页和书籍。
2. 了解并安装Linux系统,学会使用常用命令行。
3. 了解ftp、tcp、udp等协议。
4. 了解调用语音模块的相关知识。
5. 学习Qt的使用。
二、问题分析
1. 配置Linux系统,使虚拟机能够与局域网中其他虚拟机互通。
2. 用socket编程搭建服务器与客户端。
3. 实现服务器与客户端的连通,搭建聊天室。
4. 显示聊天室在线人数。
5. 实现发送文字信息的功能。
6. 利用协议发送文件。
7. 调用语音模块实现语音消息的传输。
三、项目创新点
1. 编写自定义协议,实现消息传输的加密性。
2. 实现信息私聊功能。
3. 实现文件查看和定向传输功能。
关键问题讨论
一、问题分析
(一) 配置虚拟机网络。
配置虚拟机网络为桥接模式,使其能够访问局域网中其他虚拟机。
首先虚拟机网络模式分为Bridged(桥接模式)、NAT(网络地址转换模式)、Host-Only(仅主机模式)。桥接模式就是将主机网卡与虚拟机虚拟的网卡利用虚拟网桥进行通信。在桥接的作用下,类似于把物理主机虚拟为一个交换机,所有桥接设置的虚拟机连接到这个交换机的一个接口上,物理主机也同样插在这个交换机当中,所以所有桥接下的网卡与网卡都是交换模式的,相互可以访问而不干扰。
因此这里我们采用桥接模式。
(二) 利用socket编程实现服务器、客户端连通,并传输文字信息。
Socket套接字是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口。
在Linux系统下,我们利用socket完成了服务器和客户端的建立,基于TCP协议在服务器和客户端之间建立通信通道。
(三) 利用scp协议实现文件传输。
FTP 基于TCP来传输文件,明文传输用户信息和数据。
SFTP 基于SSH来加密传输文件,可靠性高,可断点续传。
SCP 是基于SSH来加密拷贝文件,但要知道详细目录,不可断点续传。
通过考察和尝试,我们最终选用scp协议实现文件传输。
(四) 实现语音消息传输。
语音信号在网络中简化大致是mic采样(模数转换)、编码、解码、speaker输出(数模转换), 所以延时是避免不了的,但是现在的技术可以让这个延时的过程变得非常非常短,快到人感觉不到的程度。
我们通过阅读相关资料,最终选定使用语音模块和命令行实现这个功能。
具体实现
(一)利用socket编程实现服务器、客户端连通,并传输文字信息。
这一步在第一篇知乎文章中已经有完整详细的解释,有兴趣的朋友们可以移步查看~
(二) 利用scp协议实现文件传输。
SCP协议基于SSH协议,它使用建立的SSH连接隧道作为数据传输通道,而SSH连接隧道是安全的,因而基于SCP协议的文件传输是安全的。
SCP协议分为SCP Client和SCP Server。SCP Client和SCP Server都包含有“从本地复制文件传输给对方”和“从对方获取文件复制到本地”的功能。但是SCP Server跟常见的Server不同,它不是“持续运行,监听端口”的,而是被触发运行的(比如Tomcat Server持续运行,监听80端口)。
当SCP Client发起文件传输请求(SCP连接请求)(从SCP Client传输文件到SCP Server或者从SCP Server传输文件到SCP Client),会去调用同台机器上的SSH Client程序,接着SSH Client程序向SSH Server进行文件传输请求,在得到允许的结果后,SSH Server会建立一个SSH连接作为数据隧道,并运行同台机器上的SCP Server。
此时如果是“从SCP Client传输文件到SCP Server”的情形:接下来SCP Client从本地复制文件数据,将数据通过SSH隧道传输,SCP Server从SSH隧道读取数据,将数据写入本地存储成一个文件;
此时如果是“从SCP Server传输文件到SCP Client”的情形:接下来SCP Server从本地复制文件数据,将数据通过SSH隧道传输,SCP Client从SSH隧道读取数据,将数据写入到本地存储成一个文件。
我们使用scp协议完成客户端向服务器上传文件、从服务器查看并下载文件;向指定IP用户传输文件;群发文件等功能。
(三)实现语音消息传输。
Linux音频构架:
ALSA分为两部分:一部分是在Linux Kernel的声卡驱动,主要是对声卡硬件(支持的采样率、声道、格式等)的描述和抽象;另一部分是在User Space的alsa-lib,有一套插件机制,包括resampling、mixing、channel mapping等功能都可以通过插件实现。
对于大部分应用,最佳的选择是用ALSA的API。在上图中,APP1直接通过ALSA访问声卡,APP2通过plug插件和dmix插件访问声卡,这样遇到硬件不支持的格式或采样率,插件会帮忙自动转换。APP3通过ALSA的pulse插件使用到了PulseAudio,支持多应用同时使用。APP4则直接用PulseAudio的API播放录音。因为PulseAudio、JACK和PipeWire都以ALSA插件的方式为用户提供ALSA API的访问。
我们利用命令行arecord和aplay以及重定向输入输出来实现音频信息的传输与播放。
(四) 实现自定义协议。
互联网上充斥着各种各样的网络服务,在对外提供网络服务时,服务端和客户端需要遵循同一套数据通讯协议,才能正常的进行通讯。
已知的知名协议(http,smtp,ftp等)在安全性、可拓展性等方面不能满足需求,从而需要设计并实现自己的应用层协议。
通过分析,我们决定自定义一个协议。
采用固定边界的方法来自定协议。
协议头和协议体如下:
运行后:
运行效果
以下是几种文件传输的类型。利用不同的type实现不同的功能。
识别特定标识“A + ClientID”来识别发送语音消息。
具体实现实例:
Server
Client
以下是完整的记录:
Server:
talker@ubuntu:~/Desktop/CHATROOM$ ./chatroom_server
Init Server...
TRY: 0:22
Start to listen
client connection from: 192.168.43.207:55985, clientfd = 5
Addr:192.168.43.207
Add new clientfd = 5 to epoll
Now there are 1 clients in the chat room
read from client(clientID = 5)
client connection from: 192.168.43.12:32995, clientfd = 6
Addr:192.168.43.12
Add new clientfd = 6 to epoll
Now there are 2 clients in the chat room
read from client(clientID = 6)
read from client(clientID = 5)
read from client(clientID = 5)
private chat
read from client(clientID = 5)
scp user@192.168.43.207:/home/user/Desktop/999.txt /home/talker/Desktop/file/
999.txt 100% 565 42.8KB/s 00:00
read from client(clientID = 5)
read from client(clientID = 5)
192.168.43.207
scp /home/talker/Desktop/file/yyynb.txt user@192.168.43.207:/home/user/file/yyynb.txt
yyynb.txt 100% 565 38.5KB/s 00:00
read from client(clientID = 5)
scp user@192.168.43.207:/home/user/Desktop/999.txt /home/talker/Desktop/file/
999.txt 100% 565 38.0KB/s 00:00
scp /home/talker/Desktop/file/999.txt user@192.168.43.12:/home/user/file/
999.txt 100% 565 44.4KB/s 00:00
read from client(clientID = 5)
scp user@192.168.43.207:/home/user/audio.wav /home/talker/Desktop/file/
audio.wav 100% 938KB 2.2MB/s 00:00
scp /home/talker/Desktop/file/audio.wav user@192.168.43.12:/home/user/file/
audio.wav 100% 938KB 2.1MB/s 00:00
read from client(clientID = 6)
scp user@192.168.43.12:/home/user/audio.wav /home/talker/Desktop/file/
audio.wav 100% 375KB 2.2MB/s 00:00
scp /home/talker/Desktop/file/audio.wav user@192.168.43.207:/home/user/file/
audio.wav 100% 375KB 2.0MB/s 00:00
read from client(clientID = 6)
ClientID = 6 closed.
now there are 1 client in the chat room
read from client(clientID = 5)
ClientID = 5 closed.
now there are 0 client in the chat room
Client5:
user@ubuntu:~/Desktop/CHATROOM$ ./chatroom_client
192.168.43.200
Connect Server: 192.168.43.200 : 22
Please input 'exit' to exit the chat room
+ ClientID to private chat
@S to transfer file to server
@C to download file
@ + ClientID to transfer file privately
A + ClientID + time(sec) to send audio message privately
'ls' to check files
Welcome you join to the chat room! Your chat ID is: Client #5
There is only one in the chat room!
ClientID 6 say >>
test01
6 test 02
@S /home/user/Desktop/999.txt
upload file successfully
ls
1.cpp
777.txt
88888.txt
999.txt
audio.wav
sound_recv
sound_send
yyynb.txt
@C yyynb.txt
download file ' yyynb.txt ' successfully
@6 /home/user/Desktop/999.txt
A6 5
Recording WAVE 'audio.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
Audio message has been sent successfully
Client 6 has sent you a file
Playing WAVE 'audio.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
exit;
Client6:
./chatroom_client
192.168.43.200
Connect Server: 192.168.43.200 : 22
Please input 'exit' to exit the chat room
+ ClientID to private chat
@S to transfer file to server
@C to download file
@ + ClientID to transfer file privately
A + ClientID + time(sec) to send audio message privately
'ls' to check files
Welcome you join to the chat room! Your chat ID is: Client #6
ClientID 5 say >> test01
Client 5 say to you privately >> test 02
Client 5 has sent you a file
Client 5 has sent you a file
正在播放 WAVE 'audio.wav' : Signed 16 bit Little Endian, 频率48000Hz, Stereo
A5 2
正在录音 WAVE 'audio.wav' : Signed 16 bit Little Endian, 频率48000Hz, Stereo
Audio message has been sent successfully
EXIT