请教入门的SOCKET文件传输效率问题。

ybhzf 2014-03-05 09:37:36
在传输过程中发现效率很低,本地局域网100mb网络只能用到5%的网络带宽,不知道是何缘故,同样的机器同样的网络使用其他IM工具传输效率可用到60-90%的带宽。
传输的28.rar文件8mb,用时2分钟。
期间尝试过加大两端的read缓存大小,或者加大socket双方的接收和发送缓存大小,效果均不佳。尝试过的相关设置如下:
this.st.setTrafficClass(0x10);
this.st.setPerformancePreferences(0, 1, 2);
this.st.setTcpNoDelay(true);//关闭优化算法
this.st.setReceiveBufferSize(this.packsize);
客户端代码如下:
InputStream is=null;
BufferedInputStream bis=null;
byte[] b=null;
int zj=0;
Socket st=null;
OutputStream os=null;
BufferedOutputStream bos=null;
try
{
st=new Socket();
st.connect(new InetSocketAddress("127.0.0.1", 5000));
os=st.getOutputStream();
bos=new BufferedOutputStream(os);
b=new byte[1024*1024*5];
is=new java.io.FileInputStream("28.rar");
bis=new BufferedInputStream(is);
while((zj=bis.read(b))!=-1)
{
bos.write(b,0,zj);
}
bos.flush();
}
finally
{
b=null;
try
{
if (bos !=null) bos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
bos=null;
}
try
{
if (os !=null) os.close();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
os=null;
}
try
{
if (bis !=null) bis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
bis=null;
}
try
{
if (is !=null) is.close();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
is=null;
}
try
{
if (st !=null && !st.isClosed()) st.close();
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
st=null;
}
}

服务端代码如下:
public class YServer
{
// 默认监听端口
public static final int port = 5000;
// 最大监听数量
public static final int maxport = 10;
// 默认操作超时时间(毫秒单位)
public static final int timeout = 0;

//默认文件存放目录
public static String filedir="f:/temp/";

/**
*
*/
public YServer()
{
// TODO Auto-generated constructor stub
}

/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws Exception
{
// TODO Auto-generated method stub
ServerSocket ss = null;
InetSocketAddress isa = null;
Socket st = null;
try
{
//接收参数文件存放目录
if (args !=null && args.length>0)
{
if (args.length !=1) throw new Exception ("目录参数只能指定为1个!");
YServer.filedir=args[0];
}
if (YServer.filedir==null || YServer.filedir.trim().equals(""))
{
throw new Exception ("必须指定文件存放目录!");
}
else
{
YServer.filedir=YServer.filedir.trim();
if (YServer.filedir.endsWith("/") || YServer.filedir.endsWith("\\"))
{
}
else
{
YServer.filedir+="/";
}
File f=null;
try
{
f=new File(YServer.filedir);
if (!f.isDirectory())
{
throw new Exception ("指定的【"+YServer.filedir+"】不是一个目录!");
}
if (!f.canRead() || !f.canWrite())
{
throw new Exception ("指定的【"+YServer.filedir+"】目录没有读写权限!");
}
}
finally
{
f=null;
}
}

// 设置IP地址和端口
isa = new InetSocketAddress(YServer.port);
ss = new ServerSocket();
// 设置超时
ss.setSoTimeout(YServer.timeout);
// 绑定端口和最大连接数,ss=new ServerSocket(YServer.port,YServer.maxport);
ss.bind(isa, YServer.maxport);
// 循环接受应答
while (true)
{
// 得到连接入的网络连接
st=ss.accept();
if (st !=null)
{
//交给线程处理连接上的网络连接
new Thread(new YTrans(st,Charset.forName("GBK"))).start();
}
st=null;
// 线程休息,避免CPU 100%
Thread.sleep(500);
}
}
finally
{
isa = null;
try
{
if (st !=null && !st.isClosed())
{
st.close();
}
}
finally
{
st = null;
}
try
{
if (ss != null && !ss.isClosed())
{
ss.close();
}
}
finally
{
ss = null;
}
}
}

}

public class YTrans implements Runnable
{
/*
* 连接上的客户端
*/
private Socket st = null;
/*
* 字符集
*/
private Charset charset = null;
/*
* 客户端IP地址
*/
private String InetAddress = null;
/*
* 客户端端口
*/
private int port = 0;
/*
* 网络输入流
*/
private InputStream is = null;
/*
* 网络输出流
*/
private OutputStream os = null;
/**
* 数据包拆包大小
*/
private final int packsize = 1024*1024*5;

/**
* 是否为首次登录
*/
private boolean firstflag = false;

private FileOutputStream fs = null;
private BufferedOutputStream bfs = null;

// 默认构造函数
public YTrans()
{
}

/**
* 可初始化参数的构造函数
*
* @param st
* 连接上的客户端
* @param charset
* 字符集
*/
public YTrans(Socket st, Charset charset)
{
super();
this.st = st;
this.charset = charset;
}

/**
* @return the st 返回连接上的客户端
*/
public Socket getSt()
{
return st;
}

/**
* @param st
* the st to set 设置连接上的客户端
*/
public void setSt(Socket st)
{
this.st = st;
}

/**
* @return the charset 返回处理字符集
*/
public Charset getCharset()
{
return charset;
}

/**
* @param charset
* the charset to set 设置处理字符集
*/
public void setCharset(Charset charset)
{
this.charset = charset;
}

/**
* 业务处理逻辑
*
* @return
*/
private boolean Handle()
{
// 数据包总长度
int blen = 0;
// 临时数据对象
byte[] b = null;

try
{
// 网络连接对象为空
if (this.st == null) return false;
// 字符集编码为空
if (this.charset == null) return false;
// 网络没有连接
if (!this.st.isConnected()) return false;
// 获取网络输入输出流
if (this.is == null)
{
this.is = this.st.getInputStream();
}
if (this.is == null) return false;
this.os = this.st.getOutputStream();
if (this.os == null)
{
if (this.os == null) return false;
}
// 处理业务逻辑
b = null;
b = new byte[this.packsize];
// 读取输入流
while (true)
{
// 读取网络数据
blen = this.is.read(b);
// 判断是否读取到数据
if (blen == -1)
{
break;
}
}
// 使用后清理读取数组
b = null;
return true;
}
catch (Exception es)
{
es.printStackTrace();
return false;
}
finally
{
b = null;
}
}

@Override
public void run()
{
// TODO Auto-generated method stub
try
{
while (true)
{
if (!this.Handle()) break;
Thread.sleep(100);
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if (this.bfs != null)
{
this.bfs.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.bfs = null;
}

try
{
if (this.fs != null)
{
this.fs.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.fs = null;
}

try
{
if (this.is != null)
{
this.is.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.is = null;
}
try
{
if (this.os != null)
{
this.os.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
this.os = null;
}
try
{
if (this.st != null && !this.st.isClosed())
{
this.st.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
st = null;
}
System.out.println(new Date());
}
}
}

...全文
339 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
ybhzf 2014-03-08
  • 打赏
  • 举报
回复
除了nio,读写使用缓存外,还有什么可以加快网络数据传输的方法?
ybhzf 2014-03-07
  • 打赏
  • 举报
回复
引用 6 楼 abstruct 的回复:
应该是你程序啥地方没对吧,之前我做过一个socket发送文件的工具,2个多G,也就十来分钟的样子
有否例子可以参考,具体的测试代码就是上面发的这个,能否看看什么地方有问题,把程序放在linux的机器上发觉效率高了很多,318mb大约20秒的样子,客户机网络带宽99%的稳定占用!
安特矮油 2014-03-06
  • 打赏
  • 举报
回复
应该是你程序啥地方没对吧,之前我做过一个socket发送文件的工具,2个多G,也就十来分钟的样子
ybhzf 2014-03-06
  • 打赏
  • 举报
回复
引用 3 楼 AFer198215 的回复:
睡眠应该是发送数据方控制的,每次发个小包(比如512字节)然后小睡一会。
对于nio睡眠是发送端控制的同步阻塞的Socket操作我并没有做睡眠的动作,但目前我测试的是单线程,速度测试并不测试并发的情况。同步阻塞的io操作为何速度上不去,另外数据分包的大小建议值设置多少,设置太小网络带宽利用率超不过25%,设置过大会出现数据峰值不连续1秒是0.02%一秒是30-60%之间。
想喝咖啡的貓 2014-03-06
  • 打赏
  • 举报
回复
引用 3 楼 AFer198215 的回复:
睡眠应该是发送数据方控制的,每次发个小包(比如512字节)然后小睡一会。
想想好象不对,无视这段话吧。
想喝咖啡的貓 2014-03-06
  • 打赏
  • 举报
回复
睡眠应该是发送数据方控制的,每次发个小包(比如512字节)然后小睡一会。
ybhzf 2014-03-06
  • 打赏
  • 举报
回复
引用 1 楼 xnjnmn 的回复:
一般来说 网络编程现在都用 nio了
nio也稍微了解过同时支持异步和同步的操作,解决的是高并发效率的问题,从BIO的基础上进行拓展更接近底层API调用,但我的应用场景是大频率的文件传输(平均500kb-3mb,有时有50-100mb),nio是否适合(文件传输时本身是有一个简单的报文协议的,上述代码为了方便测试效率没有用报文),网上有资料说异步的nio发送数据时如果发送过快不适当sleep有可能出现发送错误。
xnjnmn 2014-03-05
  • 打赏
  • 举报
回复
一般来说 网络编程现在都用 nio了

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧