java 多线程文件传输_java多线程与单线程socket传输文件测试说明

上个礼拜,测试一个东西,就是单线程和多线程客户端与一个socket服务器连接,传输数据,哪一个更快。然后我写了一个程序,如下:

服务器代码

public class SocketServer {

private int port;

private ServerSocket serverSocket;

private Date date;

private static long startDate = 0;

public SocketServer (int port){

this.port = port ;

startSend();

}

public static void receiveFile(Socket socket) throws IOException

{

byte[] inputByte = null;

int length = 0;

DataInputStream dis = null;

FileOutputStream fos = null;

DataOutputStream dos = null;

String filePath = "D:/temp/"+"SJ"+new

Random().nextInt(10000)+".docx";

try {

try {

dis = new DataInputStream(socket.getInputStream());

//dos = new DataOutputStream(socket.getOutputStream());

File f = new File("D:/temp");

if(!f.exists()){

f.mkdir();

}

fos = new FileOutputStream(new

File(filePath));

inputByte = new

byte[1024];

System.out.println("开始接收数据..."+(new Date().getTime() - startDate));

while ((length = dis.read(inputByte, 0, inputByte.length)) > 0)

{

fos.write(inputByte, 0, length);

fos.flush();

}

//发送回执

dos.write(inputByte);

System.out.println("完成接收:"+filePath);

} finally {

if (fos != null)

fos.close();

if (dis != null)

dis.close();

if (socket != null)

socket.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}

public void startSend(){

int mark =0;

try {

serverSocket = new ServerSocket(port);

System.out.println("服务器已启动,端口号为:"+port+".");

System.out.println("正在等待客户端连接......");

while (true) {

try

{

System.out.println("开始监听...");

Socket socket = serverSocket.accept();

System.out.println("有链接");

if(mark==0)

{

startDate = new Date().getTime();

mark =1;

}

receiveFile(socket);

long time = new Date().getTime() - startDate;

System.out.println("总时间:"+time);

} catch (Exception e) {

System.out.println("服务器异常");

e.printStackTrace();

}

}

//socketAccept.close();

} catch (Exception e)

{

}

}

}

客户端代码:

public void connectSocketFileTrans() throws

IOException{

int length = 0;

double sumL = 0 ;

int mark = 0;

byte[] sendBytes = null;

byte[] recvBytes = null;

Socket socket = null;

DataInputStream dis = null;

DataOutputStream dos = null;

FileInputStream fis = null;

boolean bool = false;

long startTime =0;

long endTime = 0;

long l = 1;

try {

File file = new File(fileName); //要传输的文件路径

l = file.length();

if(host.equals("localhost")||host.equals("127.0.0.1")){

socket = new Socket(InetAddress.getLocalHost(),port);

}else {

socket = new Socket(InetAddress.getByName(host),port);

}

System.out.println(fileName);

startTime = new Date().getTime();//开始设置管道,以及读写数据

dos = new DataOutputStream(socket.getOutputStream());

dis = new DataInputStream(socket.getInputStream());

fis = new

FileInputStream(file);

sendBytes = new byte[1024];

recvBytes = new byte[1024];

while ((length = fis.read(sendBytes, 0, sendBytes.length)) > 0)

{

dos.write(sendBytes, 0, length);

dos.flush();

//dis.read(recvBytes, 0, recvBytes.length);

//if(Arrays.equals(recvBytes, sendBytes))

{

sumL += length;

if(mark == 0)

{

System.out.println(fileName+"已传输:"+((sumL/l)*100)+"%");

mark = 1;

}

System.out.println(fileName+"已传输:"+((sumL/l)*100)+"%");

}

//else

{

//System.out.println("传输错误");

}

}

if(sumL==l){

bool =

true;

//结束管道的读写数据

endTime = new Date().getTime();

this.timeRun = endTime - startTime;

System.out.println(fileName+"已传输:"+((sumL/l)*100)+"%");

}

}catch (Exception e) {

System.out.println("客户端文件传输异常");

bool = false;

e.printStackTrace();

} finally{

if (dos != null)

dos.close();

if (fis != null)

{

fis.close();

dis.read(recvBytes, 0, recvBytes.length);

if(Arrays.equals(recvBytes, sendBytes))

{

sumL += length;

if(mark == 0)

{

System.out.println(fileName+"已传输:"+((sumL/l)*100)+"%");

mark = 1;

}

System.out.println(fileName+"已传输:"+((sumL/l)*100)+"%");

}

else

{

System.out.println("传输错误");

}

dis.close();

}

if (socket != null)

socket.close();

}

System.out.println(bool?"成功":"失败");

}

上面都是节选的下面所用到的一部分。

第一次测试的时候,使用最终回执,即只是在一个文件传送结束后使用回执。但是我的计算运行时间的函数写在了服务器端,当服务器开始接收一个文件的时候,记录开始时间,完全就接收到所有文件的时候,记录结束时间。这时候,在本地测试的时候,多线程竟然比单线程要快一些。

然后,我写了带有回执的第二次测试代码,并且在客户端记录时间,当开始执行第一次发送文件之前,记录开始时间,当所有线程或者所有类都发送结束后,记录结束时间。这时候,在本地测试的时候,单线程就比多线程快了。

后来,我做文件io测试的时候,在多次加载文件的情况下,多线程要比单线程快一些,我就误以为是第一个测试是因为文件io的原因,才使得多线程要比单线程快,但是后来我在调试的时候,发现情况并不只是这样。

在第一个测试背景下,当我服务器开启调试的时候,等待客户端连接,客户端多线程执行,向服务器发送连接请求,将文件写入数据输出管道,即当服务器接收到连接请求,并开始记录时间的时候,客户端已经完成很大一部分数据写入管道的操作了,大概每个管道可以写入的数据为190k左右,然后管道排满之后停止写入,也就阻塞在写方法上了,此时要等待所有数据发完之后才可以继续执行。而单线程的慢的原因在于客户端在服务器开始记录时间之前,只完成了第一个文件的预读,而没有做剩余文件的预读。所以,单线程要比多线程要慢,所以这个测试是错误的。

这个错误的原因来自于,我认为客户端的连接是阻塞在构造方法上,或者是写入数据方法上的,然而并不是这样子。实际的情况是这样,服务器开启后,阻塞在等待接收连接请求,而客户端发送连接请求,服务器接收到很多连接请求,对这些连接请求生成一个对列,然后处理第一个连接请求。而客户端方面,发送完连接请求之后,继续执行,将数据写入管道,因为没有回执,所以数据会一直写入管道,直到管道被填满,然后写方法进入阻塞状态。而此时,可能服务器端还没有计时。当服务器开始正式接收连接请求之后,客户端某线程进入连接状态,在管道中的数据会直接发送过去,然后该线程的管道写方法跳出阻塞状态开始执行,继续向管道中的写入剩余数据,直到所有数据传送完成,然后线程结束。服务器接收连接队列的下一条请求,然后重复执行上面步骤。所以第一次的计算时间的时候,多线程比单线程要少很多的文件io的时间。

所以,在服务器端是单线程的情况下,单线程客户端要比多线程快一些。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值