题目:
实验一:Socket程序设计试验
【实验目的及要求】
在Uinx/Linux/Windows 环境下通过socket方式实现一个基于Client/Server 或是P2P模式的文件传输程序。
要求:要求独立完成。
【实验原理和步骤】
1. 确定传输模式:通过socket方式实现一个基于Client/Server或P2P模式的文件传输程序。
2. 如果选择的是Client/Server模式的文件传输程序,则需要分别实现客户端和服务器端程序。客户端:用面向连接的方式实现通信。采用Socket 类对象,接收服务器发送的文件并保存在特定的位置。服务器端:监听客户请求,读取磁盘文件并向客户端发送文件。注意:需要实现文件的读写操作。
3. 如果选择的是P2P模式的文件传输程序,则需要实现一个Peer程序,它即是客户端,也是服务器端。Peer程序需要实现文件上传、下载及文件读写等操作。
我选的是Client/Server传输模式,因为简单嘛。以后有空要把P2P也弄一下,稍微改写代码就行了应该。(虽然应该这种东西几乎都是不可靠加坑爹的= =)
拿到题目的时候,我第一个疑问就是:文件传输,是仅限于txt格式的文本呢?还是指的任意文件?
为什么会这样想呢,因为书上给出的流式Socket的例子是发送一个String类型的消息。我就想,如果是txt文本的话,直接用同样的方法发过去,再把缓冲区里的文本写到文件里就行了。事实证明我果然是Too simple, too naive啊。新手嘛,体谅体谅= =所以果断题意是传输任意文件。我当时没考虑直接用书本的BufferedReader和PrintWriter行不行(比如传一个文件流参数进去,以后有空回来要试试,后天还要考人工智能,所以苦逼的我就先把这问题放一放了,直觉上是可以的)。当时觉得一定有个类是可以很好解决这个问题的,于是就去百度了,发现了一篇不错的东西:http://www.blogjava.net/sterning/archive/2007/10/13/152508.html 博主这里是一个传输大文件的demo。我在其中发现了我想要的东西:DataInputStream和DataOutputStream,这两个东东可以实现文件流传输。
因为这两个类差不多,我就在帮助文档查了下前者。解释如下:
数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。DataInputStream 对于多线程访问不一定是安全的。 线程安全是可选的,它由此类方法的使用者负责。
继承关系:java.lang.Object->java.io.InputStream->java.io.FilterInputStream(没打错)->java.io.DataInputStream
看来这个具体类(抽象类InputStream的子类)有个牛逼的地方就是允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。(貌似感觉BufferedReader和PrintWriter可以搞起文件了)
不管了,先自己用着。参考样例里用了BufferedInputStream类,我没用,因为感觉不需要。而且帮助文档解释的不是特别清楚(吐槽:还是MSDN给力啊= =)。事实证明我的想法是对的。
为什么要用流式Socket呢?数据报的不行?
因为流式Socket中有一个ServerSocket类,专门用来接收请求并建立连接。很方便。
照着印象打完了,跑起,成功传输,txt,pdf和jpg都无压力。好,至少框架是OK的。剩下来就是把指定原文件改成由用户在控制台输入文件名了。
思路:用String存起来,在通过数据Socket发到服务器,服务器接收,更新路径。
其实很简单,但是也出错了。
一开始用DataInputStream和DataOutputStream传byte数组,再在服务器用toString转换,发现会乱码,导致无法读取。
于是想对策,能不能用被冷落很久了的BufferedReader和PrintWriter?想了一想,好像真行,又百度了一下,网友推荐String类型的网络传输还是用BufferedReader和PrintWriter比较省心。果断敲进去了,再跑,OK。任务完成。
还留了个疑问,getInputStream()的返回值能不能赋给多个对象?close掉其中一个对其他的有没有影响?(以后写demo检查下,今天时间赶呀)
另外今天对用InputStream和OutputStream的了解又深了些。以前老记不住JAVA的输入。不像C有scanf那么方便。现在熟悉了InputStream和BufferedReader之后,发现其实很简单:
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
把BufferedReader想象成一个缓冲区,然后传InputStreamReader进来是告诉BufferedReader,你是一个输入的缓冲区,最后再用System.in定向从哪输入。很好理解。
实验代码:
client:
1 import java.io.BufferedReader; 2 import java.io.DataInputStream; 3 import java.io.DataOutputStream; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.io.OutputStream; 8 import java.io.OutputStreamWriter; 9 import java.io.PrintWriter; 10 11 import java.net.InetAddress; 12 import java.net.Socket; 13 import java.net.UnknownHostException; 14 15 import java.util.Scanner; 16 17 18 //Client类 19 public class