失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 能够传送文件的聊天室

能够传送文件的聊天室

时间:2020-01-19 10:20:29

相关推荐

能够传送文件的聊天室

回顾最初学习Java之时,曾经做了一个类似QQ的登录界面。但那也仅仅是一个界面,并没有实现真正意义上的登陆服务器。近日学习了有关通信技术的原理,结合以前学过的知识,不仅实现了多人之间简单的文字对话,而且还能给对方传送文件。同时,在和别人交流的过程中也收获了不少心得,真可谓是“受益匪浅”啊。

实现上述的功能:

首先,得弄明白的计算机之间是怎么交流的?参阅文献,我们能够了解到:“……为了使不同计算机厂家生产的计算机能够相互通信,以便在更大的范围内建立计算机网络,ISO在1978年提出了“开放系统互联参考模型”,它将计算机网络体系结构的通信协议划分为七层,自下而上依次为:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。……”说了一大段,就自身目前的知识水平来看,底层的过程(物理层和数据链路层)还不能解释清楚,倘若从自己能够把握的层面(网络层、传输层)出发,也就就不难理解了。

在传输层,主机之间的数据传输遵循TCP,UDP协议等。其中,TCP协议是“面向连接”的协议,意思就是在正式通信之前,必须要先与对方建立起连接。就好比你给别人打电话,必须等线路接通了,双方之间才能相互通话;而UDP是“面向非连接”的,就是在正式通信前不必与对方先建立连接,不管对方状态如何就直接发送。这个与手机短信非常相似:你在发短信的时候,只需要输入对方手机号并发送出去就OK了,而不需考虑对方的状态。上述两种协议各有千秋,有差异那是因为适用于不同要求的通信环境。

在网络层,主机之间要实现网络互连,就得遵循IP协议。以太网、分组交换网等,它们相互之间不能互通,其主要原因是因为它们所传送数据的基本单元(技术上称之为“帧”)的格式不同。IP协议把各种不同“帧”统一转换成“网协数据包”格式,这种转换使所有各种计算机都能在因特网上实现互通。同时,IP还有一个重要的任务:给因特网的每一台联网设备规定一个地址,并且这个地址是唯一的。

基于以上的认识,我选择创建一个遵循TCP/IP协议的聊天室。在那之前,我们得明白“服务器”和“客户机”的概念。这就好比我们日常生活中对话一样,前者可以喻为“话题的开启者”,在等待着别人的参与,另一方是“话题的参与者” ,主动去参与别人开启的话题。。。因此,首要任务就是开启话题:Java实现网络通讯程序需要引入包下面的API。过程如下:

第一步,通俗的讲,就是一个人(暂定这个人叫A)买了一台只能够接听别人(暂定这个人叫B)来电的手机,并且给手机注册了手机号码。你可能会问,怎么会有这样的人嘛,SB?嘿嘿,勿喷,先听我娓娓道来,A买手机ss_A,并注册号码: ServerSocket ss_A= new ServerSocket(port); 其中port为“端口序号”,并且port是一个0~65535的int型十进制数;在这里,我们把每个手机号码理解为"ip地址 + port"为什么要这样,一会儿就明白了)。一台手机可能不只有一个号码哦,嘿嘿。

第二步,A等待B给 他(她) 打电话:ss_A.accept(); 这个方法会“阻塞”,也就是A一直等待,直到B给他(她)打电话。才会跳出这个方法。

第三步,B有“要事”得跟A商量,所以B得去买一部手机,并且给A打过去: Socket s_B = new Socket (ip, port); 因为每台“手机”的ip是唯一的,而“手机号码”可能不止一个,所以用“ip地址+port”表示“手机号码”就能说得过去了。。一旦B给A打电话,如果没有拨错“手机号码”的话,就能拨通,然后A与B之间的连接就建立起来,这个连接的桥梁就是s_A : Socket s_A = ss_A.accept();

第四步,既然已经连接上了,那么,接下来就可以“说话”了?嘿嘿,还差一步:要找到“话筒”和“听筒”,试想如果没有这两个,会怎么样呢。 这里有很多类型“话筒”和“听筒”噢:DataOutputStream和DataInputStream ,OutputStream和InputStream与BufferedOutputStream和BufferedInputStream等,只需选其中一种就可以了,以A为例:A的手机的“话筒”:DataOutputStream dos = new DataOutputStream(s.getOutputStream());“听筒”:DataInputStream dis = new DataInputStream(s.getInputStream()); ,B同理。

第五步,可以商量“要事”啦!!。怎么听?又怎么说? 在此之前,双方要在事先“约定”说什么话就怎么听。 还是以A为例,A要“说话" ,对着A的“话筒”说不就完了吗? 也就是 dos.writeUTF; 当然也有writeInt(); , writeByte(); writeFloat();等,就理解为“说不同的语言”吧,“听筒”也类似,对方怎么说你就怎么听。否则很有可能造成“听风就是雨”。

第六步,到这里的话很感谢您能继续阅读下去,不过我很遗憾的告诉您:“没有第六步啦!!” 既然都能够实现简单对话了,那么传送文件就不在话下了。双方要事先达成传送文件的约定,那就是定义一个“秘密口令”,如果有其中一方发出了这条“秘密口令”,那么另一方收到“秘密口令”之后就做好接收文件的准备,然后“口令的发出者”还得把 文件的基本属性:文件名称,文件大小,文件内容等发送给对方,“文件的接收者”就根据接收到的消息在自己指定的地方创建一个一模一样的文件即可。到了这一步,要做的工作就和第五步一样了。

至此,分析过程基本完成。文件传送部分的关键代码如下:

发送文件端:

//给“发送文件”按钮 添加监听器

sendFile.addMouseListener(new MouseAdapter() {

@Override

public void mouseClicked(MouseEvent e) {

JFileChooser jfc = new JFileChooser();//触发按钮之后实例化文件选择器

jfc.showOpenDialog(null);//在屏幕上居中显示对话框

File f = jfc.getSelectedFile();//获取文件选择器选中的文件

if(f != null && f.isFile()){ //如果选中的文件不为空并且就是文件

try {

String str = "THIS_IS_A_FILE_WILL_BE_SEND";//传送文件的“秘密口令”

dis = new DataInputStream(new BufferedInputStream(new FileInputStream(f.getAbsolutePath())));

dos = new DataOutputStream(s.getOutputStream());

//将文件名及长度传给客户端

dos.writeUTF(str); //写入“口令”来告诉服务器“我要传送文件给你”

dos.writeUTF(f.getName());//写入“文件名”来告诉服务器“我要传送的文件的文件名是XXX”

dos.flush();//强制输出

dos.writeLong((long) f.length());//写入“文件占用的空间大小”来告诉服务器“我要传送的文件所占用的空间大小为XXXXX”

dos.flush();//强制输出

int bufferSize = 8192;缓冲区的大小

byte[] buf = new byte[bufferSize];//开辟预定缓冲区大小的byte数组,用来存取文件数据

//将文件内容写入“输入流”

while (true) {

int read = 0;

if (dis != null) read = dis.read(buf);

if (read == -1) break;

dos.write(buf, 0, read);

}

dos.flush();//强制输出

System.out.println("文件传输完成");

String string = "您成功上传了" + f.getName() + "到服务器!";

appendMassage(string);//在“聊天记录区域”显示传送结果

} catch (IOException e1) {

e1.printStackTrace();

}

}

}

});

接收文件端:首先,读入一行字符串,以此来判断下一步的操作:

String str = dis.readUTF();//从“客户端”的“输入流”中读出字符串赋给str

然后,判断是否为 传送文件的"秘密口令",如果是,就执行接收文件的方法,否则就当作文本信息处理:

//判断是否要接收文件

if(str.contains("THIS_IS_A_FILE_WILL_BE_SEND")) {

getFile();//接收文件的方法

}

接收文件的方法如下:

//接收文件的方法

public void getFile() {

try {

String savePath = "C:\\Users\\Administrator.ACER-PC\\Desktop\\";//预存放接收文件存放的路径

int bufferSize = 8192;//缓冲区的大小

byte[] bytebuffer = new byte[bufferSize];//开辟预定缓冲区大小的byte数组,用来存取文件数据

int passedLength = 0;//已经传送的文件的大小

long fileLength = 0;//文件总长度

savePath += dis.readUTF();//存放接收文件的绝对路径 = 预存放接收文件存放的路径 + 文件名

System.out.println("dis.readUTF():" + dis.readUTF());

dos = new DataOutputStream(new BufferedOutputStream(new BufferedOutputStream(new FileOutputStream(savePath))));

fileLength = dis.readLong();

System.out.println("文件的长度为:" + fileLength + "\n");

System.out.println("开始接收文件!" + "\n");

while (true) {

int read = 0;

if (dis != null) {

read = dis.read(bytebuffer);

}

passedLength += read;//已经传送的长度 = 输入流读取的长度

if (read == -1) break;

System.out.println("文件已接收了" + (passedLength * 100 / fileLength) + "%");

dos.write(bytebuffer, 0, read);

}

System.out.println("文件接收完成,存为: " + savePath + "\n");

//fileOut.close();

} catch (Exception e) {

System.out.println("接收消息错误!!" + "\n");

return;

}

}

心得:一方面,加深了对技术的理解;另一方面,我认为更重要的是,一个人如果真的决心去做一件事,那么任何理由都不成理由.就像现在,我熬到这个点也要写好我的技术博客一样,再累再苦再难再忙,都不要忘了使自己进步,都不要忘了坚持自己的理想。只要时常用理想来激励自己,就不会迷失自己,碌碌无为。

如果觉得《能够传送文件的聊天室》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。