java TCP 接收文件(图片)

本周受Z老师之托,写了一个Java接收文件(本例为图片)的TCP服务端。转载请注明出处。

总共就一个类:Main.java, 几个注意点在代码之后,代码分享如下:

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Date;
/** TCP接收文件例子 */
public class Main {

	public static ServerSocket server; //用于接收
	public static Socket socket;
	public static int port = 9999; //要监听的本地端口
	
	public static void main(String[] args) {
		
		try {
			server = new ServerSocket(port);
			System.out.println("开始监听");
            while(true){
                Socket s = server.accept(); //阻塞
                new ReceiveThread(s).start();
            }
		}catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	/** 接收的线程 */
	private static class ReceiveThread extends Thread {
		
		private Socket s;
		private InputStream socketIs;
        private OutputStream fos;
        /** 决定本线程是否要继续的标志 */
        private boolean isConnected;
        
	    public ReceiveThread(Socket s) {
	        this.s = s;
	        isConnected = true;
	    }

	    @Override
	    public void run() {
	    	
	    	while(isConnected) {
	    		
	    		String ip = s.getInetAddress().getHostAddress();
		        System.out.println("对方是" + ip + " 等待读取");

		        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmsssss");
		        String filePath = "E:\\" + simpleDateFormat.format(new Date()) + ".jpg";

		        try {
		        	socketIs = s.getInputStream();
		            
		            byte buf[] = new byte[1024];
		            int len = 0;
		            while((len = socketIs.read(buf)) != -1){  //阻塞
		            	if(fos == null) { fos = new FileOutputStream(filePath); }
		                fos.write(buf, 0, len);
		                //怎样判断文件接收完成?
		                //1. 如果对方断开连接,本循环自动退出
		                //2. 如果对方保持连接,用超时进行判断
		                s.setSoTimeout(500); //设置500ms超时
		            }
		       
		            System.out.println("【情况 1】连接断开,传输结束");
		            
		            isConnected = false; //此处是正常断开,要结束本线程
		            
		            if(fos != null) { fos.close(); } 
		            socketIs.close();
		            s.close();
		        } catch (SocketTimeoutException eTimeout) {
		            try {
		            	/*向对方返回消息*/
			            OutputStream out = s.getOutputStream();
			            out.write( "接收完成".getBytes() );
			            
			            s.setSoTimeout(0); //重新设回不超时
			            fos.close(); //关闭文件输出流,生成正常大小的文件
			            fos = null; //重新置null,防止目录中生成一个大小为0KB的文件
			            System.out.println("【情况2】超时,本次传输结束");
		            }catch(IOException eIO) { eIO.printStackTrace(); }
		
		        }catch(IOException eIO) { eIO.printStackTrace(); }
	    		
	    	}
	    	
	    }
		 
	}
	

}


几个注意点:

1. ServerSocket的accept()方法是阻塞的,直到有新的连接,代码才往后执行。

2. InputStream的read()方法是阻塞的,直到有数据可读,代码才往后执行,读到-1停止。那什么时候才会读到-1呢?只有在对方断开连接(对方主动断开或对方程序出错等情况)的时候才会读到-1。也就是说,如果对方发了文件,但保持连接,这时服务端的read()方法就会一直阻塞,导致不知道文件是否已经接收完成,这种情况下,就只能用sokcet的超时属性进行判断,超过一定时限之后捕获TimoutException从而判定文件传输结束,开始下一次read()阻塞。

3. 只有在输出流关闭之后(调用close()方法)之后文件才会被完整写入磁盘,否则文件为0KB。



上一篇:javaSE 笔记 IO流


下一篇:Java-IO流