使用TCP实现图片上传
上一篇写到使用UDP实现文字交互,UDP和TCP各有千秋,所以现在写一个TCP上传图片的demo。
TCP通信同UDP通信区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。
在开发TCP程序时,首先需要创建服务器端程序,JDK的java.net包中提供了一个ServerSocket类。
使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上(参数port就是端口号)。
ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。
ServerSocket对象可以实现服务端程序,但只实现服务器端程序还不能完成通信,此时还需要一个客户端程序与之交互,为此JDK提供了一个Socket类,用于实现TCP客户端程序。
参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。
Socket的常用方法,如图所示。
在Socket类的常用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。
下面上代码
客户端
// 创建Socket对象,连接服务器Socket socket = new Socket("127.0.0.1",8000);
这段代码只要写TCP客户端必定出现
/*
* 实现TCP客户端,连接到服务器
* 和服务器实现数据交换
* 实现TCP客户端程序的类java.net.Socket
*
* 构造方法:
* Socket(String host,int port) 传递服务器IP和端口号
* 注意:构造方法只要运行,就会和服务器进行连接,连接失败,抛出异常
* OutputStream getOutputStream() 返回套接字的输出流
* 作用:将数据输出,输出到服务器
* InputStream getInputStream() 返回套接字的输入流
* 作用:从服务器端读取数据
* 客户端服务器数据交换,必须使用套接字对象Socket中的获取IO流,自己new流,不行
*/
package com.lty.wangluotcpPhotoUp; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; /* * 实现TCP图片上传客户端 * 实现步骤 * 1.Socket套接字连接服务器 * 2.通过Socket获取字节输出流,写图片 * 3.使用自己的流对象,读取图片数据源 * FileInputStream * 4.读取图片使用字节输出流,将图片写到服务器 * 采用字节数组进行缓冲 * 5.通过Socket套接字获取字节输入流 * 读取服务器发回来的上传成功 * 6.关闭资源 */ public class TCPClient { public static void main(String[] args) throws IOException { Socket socket = new Socket("127.0.0.1",8000); //获取字节输出流,图片写到服务器 OutputStream out = socket.getOutputStream(); // 创建字节输入流,读取本机上的数据源图片 FileInputStream fis = new FileInputStream("c:\\t.jpg"); //开始读写字节数组 int len = 0; byte[] bytes =new byte[1024]; while((len = fis.read(bytes))!=-1) { out.write(bytes,0,len); } //给服务器写终止序列 socket.shutdownOutput(); //获取字节输入流,读取服务器的上传成功 InputStream in = socket.getInputStream(); len = in.read(bytes); System.out.println(new String(bytes,0,len)); fis.close(); socket.close(); } }
服务器:
这个demo是多线程的,所以有如下代码
package com.lty.wangluotcpPhotoUp; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.Socket; import java.util.Random; public class Upload implements Runnable{ private Socket socket; public Upload(Socket socket) {this.socket=socket;} public void run() { //通过客户端连接对象,获取字节输入流,获取客户端图片 try { InputStream in = socket.getInputStream(); //将目的文件夹封装到File对象 File upload = new File("d:\\upload"); if(!upload.exists()) upload.mkdirs(); //防止文件同名被覆盖,重新定义文件名字 //规则: 域名+毫秒值+6位随机数 String filename="itcast"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg"; //创建字节输出流,将图片写入到目的文件夹中 FileOutputStream fos = new FileOutputStream(upload+File.separator+filename); //读写字节数组 byte[] bytes=new byte[1024]; int len=0; while ((len=in.read(bytes))!=-1) { fos.write(bytes,0,len); } //通过客户端连接对象获取字节输出流 //上次成功写回到客户端 socket.getOutputStream().write("上传成功".getBytes()); fos.close(); socket.close(); } catch (Exception ex) { } } }
写服务器端下面两端代码是肯定会出现
ServerSocket server = new ServerSocket(8000);
//调用服务器套接字对象中的方法accept()获取套接字对象
Socket socket =server.accept();
/*
* 实现TCP服务程序
* 表示服务器程序的类java.net.ServerSocket
* 构造方法:
* SreverSoceket(int port)传递端口号
*
* 很重要的事情:必须要获得客户端的套接字对象Socket
* Socket accept()
* 服务器可以获取到客户端的套接字对象Socket
*
*/
package com.lty.wangluotcpPhotoUp; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; public class TCPThreadServer { public static void main(String[] args)throws IOException { ServerSocket server = new ServerSocket(8000); while(true) { //获取一个客户端,必须开启新线程 Socket socket=server.accept(); new Thread(new Upload(socket)).start(); } } }
效果图
网络编程与IO密不可分,但是IO内容太过繁杂,这里就不一一说了
这里涉及到了多线程请见下回分解