Java关于个人对于Socket的理解,Socket多线程批量上传文件,适合新手

       搞软件将近三年了,回想三年来匆匆忙忙,所涉猎的东西比较驳杂,Java、android、c#、ios,当回首望去才发现,原来,想要真正精通一门语言其实还是比较困难的,因此,在今天终于是开了博客,希望能够记住自己偶尔的感悟和一些编程思想,同时,也希望能够帮助更多的人进入软件行业,同为程序员,大家互相交流新得,这样才能不断的进步,程序员的大家庭才能更轻松,若本人所写东西有不得当之处,希望五湖四海的朋友能够不吝指导,谢谢。

     话不多说,直接贴代码:

     客户端:

<span style="color:#000000;">package com.qzf.socket;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class SocketClient {

	private static List<String> fQuene = new ArrayList<String>();// 文件路径的消息队列

	public static void main(String[] args) {
		fQuene.add("E:\\2013-12-08-2.bmp");
		fQuene.add("E:\\U盘备份\\111726邱振飞_数据结构.rar");
		fQuene.add("F:\\music\\BEYOND - 光辉岁月.mp3");
		fQuene.add("F:\\迅雷下载\\MB855tools.zip");
		fQuene.add("d:\\Mavericks.cdr");
		new Thread(new Runnable() {

			@Override
			public void run() {// 开启遍历消息队列的线程检查消息队列中是否有文件需要上传
				try {
					while (true) {
						Thread.sleep(200);
						if (!fQuene.isEmpty()) {
							String fName = fQuene.remove(0);
							if (new File(fName).exists()) {
								sendFile(fName);
							}
						}
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();

	}

	static int i = 0;

	static void sendFile(String fName) {
		Socket sendSocket = null;
		try {
			sendSocket = new Socket(Configs.SERVER_IP, Configs.SERVER_PORT);
			new SendThread(sendSocket, "thread-" + ++i, fName).start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class SendThread extends Thread {
	private Socket socket;
	private String fName;
	private String fNameTemp;

	public SendThread(Socket socket, String name, String fName) {
		this.socket = socket;
		this.setName(name);
		this.fName = fName;
		this.fNameTemp= fName.substring(fName.lastIndexOf('\\'));//这里是取得文件的名称,不带路径,一般用文件分隔符,这里我偷懒了
	}

	@Override
	public void run() {
		try {
			Thread.sleep(1000);
			OutputStream os = socket.getOutputStream();
			os.write(fNameTemp.getBytes("utf-8"));//将文件名称发送过去
			InputStream is = socket.getInputStream();
			byte[] revBuff = new byte[1];
			is.read(revBuff);//接收服务端传回的握手结果
			int result = revBuff[0];//自行处理,可以不处理,但是要read握手结果,表示对方已经接收到文件名称
			System.out.println(result);
			if(result == 1){//表示成功接收文件名,我自定义的返回结果为1
				System.out.println("start send file:" + fName);
				File sendFile = new File(fName);
				FileInputStream fis = new FileInputStream(sendFile);
				byte[] buffer = new byte[Configs._BUFFER_SIZE];
				int fLen = (int)sendFile.length();//文件大小
				//接下来打包发送文件,将字节数组的前四个字节放置文件的大小,当然,也可以像前面一样握手,这里不再进行握手
				byte[] fLenBuff = Utils.int2bytes(fLen);
				for(int i=0; i<fLenBuff.length; i++){
					//将文件大小放到传送的缓存数组中,待发送,这里就是简单的自定义传输协议了,包头4个字节放文件大小,后面是文件内容
					//实际操作中,我们都是这么组包的,文件名等内容也是一起组包的,不过为了方便理解,这里介绍了握手操作,以及read这个
					//阻塞方法的应用,其实都是自定义传输协议,不过,如果商用,就是组协议包,这样比较通用,理解之后,随便自定义
					buffer[i] = fLenBuff[i];
				}
				//sendLen 记录已经发送的字节数,可用于断点续传,也可用来标识上传进度
				int read, sendLen = fis.read(buffer, fLenBuff.length, buffer.length - fLenBuff.length);
				os.write(buffer);
				sendLen += fLenBuff.length;
				while((read = fis.read(buffer, 0, buffer.length)) > 0){//循环发送输入流读取到的数据
					sendLen += read;
					os.write(buffer, 0, read);
					if(sendLen == fLen)//发送完成
						break;
				}
				byte[] overOuffer = new byte[1024];
				int overLen = is.read(overOuffer);
				System.out.println("send over:" + new String(overOuffer, 0, overLen, "utf-8"));
				os.close();
				fis.close();
				is.close();
				socket.close();
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}</span>

服务端:

<span style="color:#000000;">package com.qzf.socket;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketReceiveServer {

	private static ServerSocket linstener = null;
	private static boolean isRunning = false;

	public static void main(String[] args) {
		isRunning = true;
		new Thread(new Runnable() {// 启动线程监听是否有连接上来

					@Override
					public void run() {
						try {
							linstener = new ServerSocket(Configs.SERVER_PORT);
							System.out.println("准备就绪..");
						} catch (IOException e) {
							System.out.println("linstenner exception:"
									+ e.toString());
						}

						while (isRunning) {
							try {
								Thread.sleep(90);
								Socket socket = linstener.accept();// 阻塞监听,获取socket实例
								System.out.println("有新连接上来..");
								new ReceiveThread(socket).start();// 开启新线程处理socket的数据
							} catch (InterruptedException e) {
							} catch (IOException e) {
							}
						}

					}
				}).start();
	}
}

class ReceiveThread extends Thread {
	private Socket revSocket = null;

	public ReceiveThread(Socket revSocket) {// 构造器实例化socket
		this.revSocket = revSocket;
	}

	@Override
	public void run() {
		System.out.println("接收线程开始启动");
		byte[] buffer = new byte[Configs._BUFFER_SIZE];
		// 接收到的字节数
		InputStream is;
		OutputStream os ;
		try {
			is = revSocket.getInputStream();
			os = revSocket.getOutputStream();
			int received = is.read(buffer);
			if (received > 0) {
				String fName = new String(buffer, 0 , received, "utf-8");
				System.out.println("开始接受:" + fName);
				os.write(new byte[]{1});//返回握手结果1
				// length文件的长度,receive已接收的文件长度
				is.read(buffer);
				int receive, length = Utils.bytes2int(buffer);//将收到的数组前四字节转化得到文件大小
				System.out.println(fName + " size:" + length + " B");
				FileOutputStream fos = new FileOutputStream(new File(Configs.TEST_ROOT_DIR + fName));
				fos.write(buffer, 4, buffer.length - 4);//这边的-4指的 是客户端发过来的文件大小的4个字节
				received = buffer.length - 4;
				while((receive = is.read(buffer, 0, buffer.length)) > 0){
					fos.write(buffer, 0, receive);
					received += receive;
					if(received == length){//接收完毕
						os.write((fName + " Recevice OK.").getBytes("utf-8"));//发送接收成功给客户端
						break;
					}
				}
				System.out.println("rev over");
				fos.close();
				is.close();
				os.close();
				revSocket.close();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}
</span>



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值