文件上传分析:
所谓的文件上传(客户端)就是首先的通过输入流将文件读取到内存中,然后在后再通过套接字输出流将文件写入到服务器端,然后就可以通过套接字输入流来读取服务器端返回的结果了。具体的事例代码如下
public class UploadClient{
public static void main(String []args){
//1.创建一个客户端的套接字流对象
Socket s = new Socket("192.168.1.117",10000);
//读取文件的位置及具体的文件名,表示上传的是c盘下的demo.txt文件。
File file = new File("C:\\demo.txt");
//2、创建一个读取文件的流对象,为了提高读取的效率这里采用缓冲流的形式来读取
BufferedReader bur = new BufferedReader(new FileReader(file));//注意这里是的FileReader就是一个转化流,所以就没有必要再写InputStreamReader了,并且这里是上传文件,所以就要使用文件流。
//创建一个输出流的套接字,将文件写入到套接字的输出流中,意思就是不断的从输入流中读取数据然后写入到套接字数据流中,写入到服务器中去。
PrintWriter out = new PrintWriter(s.getOutputStream(),true)//这句表示的就是将套接字字符流包装成一个字符流,并且实时的刷新。
String line = null;
while(bur.readline()!=null){
out.writer(line);
}
//这句的作用就是告诉服务器文件读取完了,如果没有这句的话就会出现到不到服务器的返回的信息的,因为读取的方法是阻塞式的,服务器端还是在不断的读取数据的。
s.shutdownOutput();
//通过套接字输入流对象来取服务器端返回的数据
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String str = bufIn.readLine();
System.out.println(str);
//关闭相应的流对象
bufr.close();
s.close();
}
}
服务器端代码:服务器端就是不断的通过套接字流来读取套接字客户端传递过来的数据,然后在通过一个输出流来写入到服务器端的目录下:
public class UploadServer {
public static void main(String[] args) throws IOException {
//1创建一个服务器端的套接字服务这里要指定端口
ServerSocket ss = new ServerSocket(10000);
//2,通过服务器端的套接字对象得到相应的客户端套接字对象。
Socket s = ss.accept();
//3,通过获得的客户端的套接字对象来获取套接字的输入流,来读取客户端发送过来的内容。
BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
//4,将读取的内容通过一个输出流来写入到服务器端的具体的目录下
BufferedWriter bufw = new BufferedWriter(new FileWriter("c:\\server.txt"));
String line = null;
while((line=bufIn.readLine())!=null){//这里的套接字读取时一个阻塞式的方法,所以当客户端写入套接字流结束的时候就要调用shutdownOutput()方法了,否则就一直的得不到服务端的返回数据,因为一直在循环里面,没有结束的标识的,Java代码是以\r\n为标识的
bufw.write(line);
bufw.newLine();//目的是换行
bufw.flush();//刷新缓冲区
}
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("上传成功");
bufw.close();
s.close();
ss.close();
}
}
服务器端的多线程技术:
通常在服务器端采用的都是多线程的技术,因为服务器端的accept()方法是一个阻塞式的方法,如果某一个客户端访问的话那么其他的客户端就是不能访问的,为了解决这个问题就可以采用多线程的技术,主线程不断的获取客户端的套接字对象,获取到了之后然后新建一个线程,然后主线程就继续的监视获取客户端的套接字对象,而创建的一个新的线程就可以操作具体的任务了,但是这个任务是根据不同的套接字对象来实现的,所以这里的成员变量要是一个获取的客户端的套接字对象,然后通过这个对象来做具体的操作功能。具体的实例代码如下:(客户端和上面的一样)
public class UploadPicServer {
public static void main(String[] args) throws IOException {
//创建tcp的socket服务端。
ServerSocket ss = new ServerSocket(10000);
while(true){
Socket s = ss.accept();
new Thread(new ClientTask(s)).start();
}
// ss.close();这里是不断的获取客户端对象没有必要关闭服务端的套接字了
}
}
ClientTask类:这个类的作用就是根据不同的客户端执行不同的任务(通过创建新的线程来执行的)这里的代码是参照网上的实例写的。
public class ClientTask implements Runnable {
private static final int SIZE = 1024*1024*2;
private Socket s;
public UploadTask(Socket s) {
this.s = s;
}
@Override
public void run() {
int count = 0;
try{
// 读取客户端发来的数据。
InputStream in = s.getInputStream();
// 将读取到数据存储到一个文件中。
File dir = new File("c:\\pic");
if (!dir.exists()) {
dir.mkdirs();
}
File file = new File(dir, ip + ".jpg");
//如果文件已经存在于服务端
while(file.exists()){
file = new File(dir,ip+"("+(++count)+").jpg");
}
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
if(file.length()>SIZE){
System.out.println(ip+"文件体积过大");
fos.close();
s.close();
System.out.println(ip+"...."+file.delete());
return ;
}
}
// 获取socket输出流,将上传成功字样发给客户端。
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
}catch(IOException e){
}
}
}
对客户端和服务器端的理解:
客户端就是发送求,而服务器端就是处理和响应服务器端请求的,常见的服务器端有tomcat,其实写一个Java类也可以当做服务器来使用,服务器里的代码通过套接字来通信,事例代码如下:
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8080);
Socket s = ss.accept();
System.out.println(s.getInetAddress().getHostAddress()+".....connected");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
//给客户端一个反馈信息。
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>欢迎光临</font>");
s.close();
ss.close();
}
然后就可以通过浏览器中输入本机的IP地址和对应访问了,在浏览器中将返回的是‘欢迎光临’的内容,当然也可以模仿浏览器端的。