您的位置:首页 > 编程语言 > Java开发

java socket 属性设置

2015-09-23 18:11 387 查看
//解析服务器地址和端口号

int dotPos = ipAddr.indexOf(':');

String ip = ipAddr.substring(0, dotPos).trim();

int port = Integer.parseInt(ipAddr.substring(dotPos+1).trim());

InetSocketAddress endpoint = new InetSocketAddress(ip , port);

Socket socket = null;

OutputStream out = null;

InputStream in = null;

try {

socket = new Socket();

//设置发送逗留时间2秒 //中断后未传输数据可传输的时间(秒),defalut false

socket.setSoLinger(true, 2);

//设置InputStream上调用 read()阻塞超时时间2秒

socket.setSoTimeout(2000);

//对于Socket和SeverSocket如果需要指定缓冲区大小,必须在连接之前完成缓冲区的设定。

//设置socket发包缓冲为32k;

socket.setSendBufferSize(32*1024);

//设置socket底层接收缓冲为32k

socket.setReceiveBufferSize(32*1024);

//关闭Nagle算法.立即发包

socket.setTcpNoDelay(true);

//连接服务器

socket.connect(endpoint);

//获取输出输入流

out = socket.getOutputStream();

in = socket.getInputStream();

//输出请求

out.write(datas);

out.flush();

//接收应答

BufferedReader br = new BufferedReader( new InputStreamReader(in) ,

4096);

StringWriter received = new StringWriter(4096);

char[] charBuf = new char[4096];

int size =0;

char lastChar = 0;

do {

System.out.println(charBuf);

size = br.read(charBuf , 0 , 4096);

System.out.println(size);

lastChar = charBuf[size-1];

if(lastChar == 0){

received.write(charBuf, 0, size - 1);

}

//System.out.println(received.toString());

}while(lastChar != 0);

return received.toString();

} finally {

if (out != null) {

try {

out.close();

} catch(Exception ex) {

ex.printStackTrace();

}

}

if (in != null) {

try {

in.close();

} catch(Exception ex) {

ex.printStackTrace();

}

}

if (socket != null) {

try {

socket.close();

} catch(Exception ex) {

ex.printStackTrace();

}

}

}

}

在创建Socket后,系统会为新创建的套接字分配缓冲区空间。这时套接字已经具有了输入缓冲区和输出缓冲区。 缓冲区大小需要根据具体情况进行设置,一般要低于64K(TCP能够指定的最大负重载数据量,TCP的窗口大小是由16bit来确定的),增大缓冲区可以增大网络I/O的性能,而减少缓冲区有助于减少传入数据的backlog(就是缓冲长度,因此提高响应速度)。

对于Socket和SeverSocket如果需要指定缓冲区大小,必须在连接之前完成缓冲区的设定。

对于缓冲区空间的设定,要根据具体情况来定,如果存在大量的长信息(比如文件传输),将缓冲区定义的大些,可能更好的利用网络资源,如果更多的是短信息(比如聊天消息),使用小的缓冲区可能更好些,这样刷新的速度会更快。一般系统默认的缓冲大小是8*1024。除非对自己处理的情况很清晰,否则请不要随意更改这个设置。

http://blog.sina.com.cn/s/blog_616e189f0100s3px.html


TCP 调优

参考:http://www.onlamp.com/pub/a/onlamp/2005/11/17/tcp_tuning.html

TCP(Transmission Control Protocol)使用一个"拥塞窗口"来判断每次应该发送多少包到网络。拥塞窗口越大,吞吐量越高。拥塞窗口是由TCP的“慢启动”和“拥塞回避”算法共同决定的。而最大拥塞窗口和Socket的缓冲区大小有关。每一个Socket缓冲区都有一个默认的大小,但可以在程序中进行修改(如上面的操作)。一些操作系统有一个内核强制的最大缓冲区大小,这需要设置操作系统参数进行修改。

为了得到最大的吞吐量,必须对TCP socket的缓冲区大小进行调优。如果缓冲区设置的太小,则TCP的拥塞窗口就不会完全开启,这是发送者是瓶颈;如果缓冲区设置得太大,则发送者可能让接受者溢出,这时会发生丢包和拥塞窗口减半/关闭的可能。如果用充足的内存,大的发送者窗口也不是很大的问题。


计算TCP缓冲区大小

假设没有网络拥塞和丢包,则网络吞吐量直接和TCP缓冲区大小和网络延迟有关。网络延迟是一个包在网络中传输所用的时间。计算出吞吐量为:

吞吐量 = 缓冲区大小 / 网络延迟

举例来说,从Sunnyvale 到Reston 的网络延迟为40ms,windowsXP的默认TCP缓冲区为17520bytes,那么

17520 bytes / 0.04 seconds = 3.5 Mbits / second
Mac OS X 是64K,所以其能达到 65936 B / 0.04 s = 13Mb / s

大多数网络专家认为较优的TCP缓冲区大小是网络的两倍延迟(delay times)乘以带宽

buffer size = 2 * delay * bandwidth

使用ping命令可以得到一次RTT时间,也就是2倍延迟,那么

buffer size = RTT * bandwidth

继续上面例子,ping返回的值为80ms,所以TCP缓冲区大小应该为

0.08s * 100Mbps / 8 = 1MByte


设置TCP缓冲区大小

如前所属,TCP有两个地方设置缓冲区大小:默认缓冲区大小和最大缓冲区大小。用户程序可以修改默认缓冲区大小,但是最大缓冲区大小需要操作系统管理员权限才能修改。现代大多数Linux系统的最大缓冲区大小为256K。windows默认没有最大缓冲区,但是管理员可以设置。需要同时改变接收和发送缓冲区大小。只改变发送缓冲区不会有作用,因为TCP商量缓冲区大小时是根据两个中较小的来确定缓冲区大小。较常见的做法是,设置服务器端的缓冲区大小较大(1024K),然后让客户端来决定优化的缓冲区大小值。在Java里面可以使用setSendBufferSize和setReceiveBufferSize,C使用setsockopt。Linux下设置时,可能会是设置的值的两倍。

设置最大TCP缓冲区

Linux下添加下面内容到/etc/sysctl.conf,然后运行sysctl -p

# increase TCP maximum buffer size
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

# increase Linux autotuning TCP buffer limits
# min, default, and maximum number of bytes to use
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

其他系统下可以参照:http://fasterdata.es.net/host-tuning/

注意

在Linux 2.4版本后加入可发送端自动调整缓冲区大小的功能
在Linux 2.6.7版本后加入了服务器端自动调整缓冲区大小的功能
这就解释了实验室数据和上面红色文件的冲突
检测网卡是否为全双工: TCP Tuning Guide

http://blog.csdn.net/s_yangbin/article/details/9128321

经测试,当服务器端设置缓冲区为1MB时,系统只把缓冲区设置为了127KB,应该是默认的最大值。经过设置最大TCP缓冲区后,

Linux下添加下面内容到/etc/sysctl.conf,然后运行sysctl -p,服务器缓冲设置为了1MB。下载速度明细提升了。

try {

ServerSocket ss = new ServerSocket(port);

Executor service = Executors.newCachedThreadPool(); // Dispatch svc

// Run forever, accepting and spawning a thread for each connection

while (true) {

Object[] obj = hmDownTotalSize.keySet().toArray();

if (obj.length > 100) {

hmDownTotalSize.clear();

}

Socket socket = ss.accept();

SocketAddress remoteAddress = socket.getRemoteSocketAddress();

String ipAddress = remoteAddress + "";

ipAddress = ipAddress.substring(1, ipAddress.indexOf(":"));

if (StringServer.hmDownTotalSize.get(ipAddress) == null) {

StringServer.hmDownTotalSize.put(ipAddress, downTotalSize);// 设置全局默认的数据包大小

}

socket.setReceiveBufferSize(downBufferUnit);

socket.setSendBufferSize(downBufferUnit);

int receiveBufferSize = socket.getReceiveBufferSize();

int sendBufferSize = socket.getSendBufferSize();

final LogSvr logSvr = new LogSvr();

final File tmpLogFile = new File("speedTest.log");

StringBuffer log = new StringBuffer();

log.append(

"\n" + ipAddress + "----------the socket's created.\n")

.append(ipAddress

+ "----------the socket's receiveBufferSize is--- "

+ receiveBufferSize / 1024 + " KB\n")

.append(ipAddress

+ "----------the Socket's sendBufferSize---------"

+ sendBufferSize / 1024 + " KB\n");

logSvr.logMsg(tmpLogFile, log.toString());

service.execute(new EchoProtocol(socket));

}

谢谢了,循环发送我是知道的,可是您说的 “发送接收缓存的大小”在哪里设置呢? 不会是指 char *p=new char[100]这种吧,还是指通过某个SOCKET函数设置的TCP发送接收缓存区大小? 还有就是设置完“发送接收缓存大小”了之后,每次send是不是不可以超过发送端的大小?

linux下man 7 socket里看SO_RCVBUF和SO_SND_BUF,windows不明。

另外,你调用send不表示你的数据会立即发出去,当前能发送多少数据取决于:1.nagle算法是否打开,2.内核里为发送socket准备的发送缓存大小(协议栈需要拷贝一次发送数据以便丢包时重传),3.对方宣告的接收窗口大小,4.自己目前的拥塞窗口的大小。其它应该还有一些影响因素。这还只是在TCP层。IPv4的话还有一个IP包65536(64KB)的硬限制,以及链路层的MTU的限制。总之从send的角度看应该没有办法确定你从网卡出去的下一帧,或者传给网卡的下一个IP包或者走到网络层的下一个TCP包是多大的,而你也不需要知道这些。如果非要强制一个包的大小,那么用UDP吧,只是你可能就需要自己维护重传,包的顺序,以及MTU探测这些事情了。


从缓冲上看阻塞与非阻塞socket在发送接收上的区别

http://wenku.baidu.com/view/7ecc3b6d561252d380eb6e28.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: