文档章节

Java网络学习笔记3:设置Socket选项(补充)

berg-dm
 berg-dm
发布于 2015/11/19 19:56
字数 1691
阅读 167
收藏 5

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

 接上一篇博文,在小小添加几个Socket选项, 

    4.SO_LINGER选项:

//设置该选项:
public void setSoLinger(boolean on,int seconds) throws SocketException  // 注意第二个参数以秒为单位,并非毫秒
//读取该选项:
public int getSoLinger() throws SocketException

    SO_LINGER选项用来控制Socket关闭时的行为,默认情况下,当执行Socket的close()方法,该方法会立即返回,但底层的Socket实际上并不立即关闭,它会延迟一段时间知道发送完所有剩余的数据,才会真正关闭Socket,才断开连接。

但对于以下情况:  

socket.setSoLinger(true,0); //该方法也会立即返回,但底层的Socket也会立即关闭,所有未发送完的剩余数据被丢弃。
                                        //还在网络上传输,但是未被接收方接收的数据,
socket.setSoLinger(true,1000); 
// 而该方法不会立即返回,而是进入阻塞状态。 只有当底层的Soket发送完所有的剩余数据或阻塞时间已经超过了1000秒,也回返回,但是剩余未发送的数据被丢弃。

//对于该选项,尝试着让服务器端先睡眠一会,再开始接受数据:   

//服务器端程序:
public class SimpleServer {
	public static void main(String[] args) throws Exception {
		ServerSocket server = new ServerSocket(7777);
		Socket socket = server.accept();
		System.out.println("服务器困了,于是决定休息会...");
		Thread.sleep( 1000*10 );   // 睡眠10秒。
		System.out.println("服务器终于睡醒了,然后开始接受数据:");
		InputStream in  = socket.getInputStream();
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		byte[] buff = new byte[1024];
		int length = -1;
		while( ( length = in.read(buff) ) != -1){
			buffer.write(buff,0,length);
		}
		System.out.println( new String( buffer.toByteArray() )); //把字节数组转换成字符串。
	}
}


//客户端程序:
public class SimpleClient {
	public static void main(String[] args) throws Exception {
		Socket socket = new Socket("localhost",7777);
		//socket.setSoLinger(true, 0);    //(1)  该条件下,会强行关闭底层的Socket,导致所有未发送数据丢失,而服务器算接受方睡醒后接受数据,由于底层Socket关闭,则会抛出SocketException: Connection reset.
		//socket.setSoLinger(true, 300);  //(2) 注意Socket关闭时间,实际上会等待一段时间在关闭
		OutputStream out = socket.getOutputStream();
		StringBuffer sb = new StringBuffer();
		String str = "关于对setSoLinger选项的设置:";
		sb.append(  str );
		for( int i=1;i<=10000;i++){  // 需注意jvm堆栈的设置。
			sb.append( i );
		}  
		System.out.println( sb );
		out.write( sb.toString().getBytes() );
		System.out.println("开始关闭Socket: ");
		long start = System.currentTimeMillis();
		socket.close();  // 注意不同条件下(1)与(2)的关闭的时间
		long end = System.currentTimeMillis();
		System.out.println("关闭Socket所用时间为: " + (end - start ) +"ms" );
	}

}

5.SO_RCVBUF选项: 该选项用于 输入数据 的缓冲区的大小。

//设置该选项:
public void setReceiveBufferSize(int size) throws SocketException
//读取该选项:
public int getReceiveBufferSize() throws SocketException

 6.SO_SNDBUF选项:该选项用于 输出数据的缓冲区的大小。

//设置该选项:
public void setSendBufferSize(int size) throws SocketException;
//读取该选项:
public void getSendBufferSize() throws SocketException;
public class SocketBufferDemo {
	public static void main(String[] args) throws SocketException {
		Socket socket = new Socket();//不带参的构造方法,不会试图建立与服务器端的连接.
		
		//默认情况下的输入输出缓冲区的大小:
		int rcvbuf = socket.getReceiveBufferSize();  // 输入缓冲区大小
		int sndbuf = socket.getSendBufferSize();  //输出缓冲区大小
		System.out.println( rcvbuf  + "\t" + sndbuf );
		
		//重新设置输入输出缓冲区的大小再输出结果:
		socket.setReceiveBufferSize( 1024*32 );
		socket.setSendBufferSize( 1024*32 );
		System.out.println( socket.getReceiveBufferSize()+"\t"+socket.getSendBufferSize() );
	}
}

7.SO_KEEPALIVE选项: 

//设置该选项:
public void setKeepAlive(boolean on) throws SocketException
//读取该选项:
public int getKeepAlive() throws SocketException

    当该选项为true时,表示底层的TCP实现会监视该连接是否有效。当连接处于空闲状态(即连接的两端没有互相传送数据)超过2H,本地的TCP实现会发送一个数据包给远程的Socket。如果远程Socket没有发回响应,TCP实现就会持续尝试11分钟,直到接收到响应为止。如果在12分钟内未收到响应,TCP实现就会自动关闭本地Socket,断开连接。(在不同的网络平台上,TCP实现尝试与远程Socket对话的时限会有所差别)。

    该选项默认值为 false,即表示TCP不会监视连接是否有效,不活动的客户端可能会永久存在下去,而不会注意到服务器已经崩溃。

对于KeepAlive这种系统底层的机制(用于系统维护每一个tcp连接的),可在认识到另一种新的概念,即心跳线程:

链接网址:①; http://code.taobao.org/p/tfs/wiki/dataserver/background/  <心跳线程简单介绍>

                ②: http://blog.csdn.net/xuyuefei1988/article/details/8279812  《关于心跳包机制》

                 ③:http://blog.sina.com.cn/s/blog_616e189f0100s3px.html <这篇也不错,Socket缓冲区探讨>

8.OOBINLINE选项:

//设置该选项:
public void setOOBInline(boolean on ) throws SocketException
//读取该选项:
public void getOOBInline() throws SocketException


public void sendUrgentData(int data) throws IOException  
    //虽然sendUrgentData的参数data是int类型,但只有这个int类型的低字节被发送(即一个字节,8位),其它的三个字节被忽略。

    该选项为true时,表示支持发送一个字节的TCP紧急数据。Socket类的sendUrgentData( int data ) 方法用于发送一个字节(8位)的TCP紧急数据。 

而为false时,表示当接收方收到紧急数据时不作任何处理,直接丢弃。

但是问题是接收方会把接收到的紧急数据与普通数据放在同样的队列中,除非使用一些更高层次的协议,否则接收方处理紧急数据的能力非常有限,当紧急数据到来时,接收方不会得到任何的通知,因此接收方很难区分普通数据与紧急数据,只好按同样的方式处理他们。

//服务端代码:
public class OOBInlineServer {
	public static void main(String[] args) throws Exception {
	    ServerSocket serverSocket = new ServerSocket(7777);
            System.out.println("服务器已经启动,端口号:7777");
            while (true)
            {
                Socket socket = serverSocket.accept();
                // 须在服务端中也设置为true,否则无法接受到客户端发送过来的紧急数据:
                socket.setOOBInline(true); 
                InputStream in = socket.getInputStream();
                InputStreamReader inReader = new InputStreamReader(in);
                BufferedReader bReader = new BufferedReader(inReader);
                System.out.println(bReader.readLine());
                System.out.println(bReader.readLine());
                socket.close();
            }
	}

}

//客户端代码:
public class OOBInlineClient {
	public static void main(String[] args) throws Exception {
	    Socket socket = new Socket("localhost", 7777);
            socket.setOOBInline(true);
            OutputStream out = socket.getOutputStream();
            OutputStreamWriter outWriter = new OutputStreamWriter(out);
            outWriter.write(67);              // 向服务器发送字符"C"
            outWriter.write(" Hello World\r\n ");
            socket.sendUrgentData(65);        // "A"
            socket.sendUrgentData(68);        // "D"
            outWriter.flush();
            socket.sendUrgentData(322);        // "B"  322分布在两个字节上,但是其低位为:0100 0010 即刚好跟 66 一样,
            socket.close();
	}
}

    猜测下上述输出结果: 猜测可能为: 

        C Hello World 

        A D   B

但正常结果输出为:

        

由此可见:使用sendUrgentData()方法发送数据后,系统会立即将这些数据发送出去,而使用write()(首先是将数据存放在了缓冲区)发送数据,必须要使用flush()方法才会真正发送数据。

另外注意的是:在使用 setOOBInline()方法时,要注意必须在客户端和服务端程序同时使用该方法,打开SO_OOBInline选项,否则无法命名sendUrgentData来发送数据。



© 著作权归作者所有

berg-dm
粉丝 26
博文 98
码字总数 88970
作品 0
深圳
程序员
私信 提问
基于tcp和udp的socket实现

本文介绍如何用Java实现Socket编程。首先介绍Java针对Socket编程提供的类,以及它们之间的关系。然后分别针对TCP和UDP两种传输层协议实现Socket编程。 1 Java中的Socket编程接口介绍 Java为S...

chjuaner
2017/11/07
85
0
12.5-全栈Java笔记:Java网络编程(三)

上节回顾:在学习了Socket在建立客户端和服务器单项通讯中,分别创建独立的Socket,并通过Socket的属性。 那么如何将两个Socket进行连接,从而达到客户端和服务器之间建立输入输出流进行通信...

全栈Java
2018/06/26
0
0
分享一个简单易用的RPC开源项目—Tatala

这个项目最早(2008年)是用于一个网络游戏的Cache Server,以及一个电子商务的Web Session服务。后来不断增加新的功能,除了Java还支持C#,到现在已经可以用它来开发网络游戏的服务器。等过些...

zijan
2014/04/08
207
1
一份关于 Java、Kotlin 与 Android 的学习笔记

JavaKotlinAndroidLearn 这是一份关于 Java 、Kotlin 、Android 的学习笔记,既包含对基础知识点的介绍,也包含对一些重要知识点的源码解析,笔记的大纲如下所示: Java 重拾Java(0)-基础知...

叶应是叶
2018/08/08
0
0
java编程好文章链接收集

JNDI配置原理详解 ExtJS学习笔记系列 .java中的io系统总结及一些常用的操作 java面试笔试题总结 Java基础:三步学会Java Socket编程 HTTP详解 SpringSide开发实战 SVN与源代码管理 Linux和J...

长平狐
2012/11/12
79
0

没有更多内容

加载失败,请刷新页面

加载更多

网易易盾深度学习模型工程化实践

深度学习大热之后受到大量关注,大部分刚接触深度学习的同学,注意力大都集中在如何调整参数/数据/网络结构,如何达到预期的精度/召回率/准确率等。 然而,深度学习模型应用的整个流程里面还...

网易易盾
7分钟前
3
0
hibernate meger

转: 在Hibernate中,有save、persist、savaOrUpdate、merge等方法有插入数据的功能。前三者理解起来较后者容易一些,merge方法从api中的介绍就看以看出它是最复杂的。下面是Hibernateapi中的...

牛po
13分钟前
4
0
人们为什么在Python脚本的第一行上编写#!/ usr / bin / env python shebang?

在我看来,如果没有该行,文件运行相同。 #1楼 您可以使用virtualenv尝试此问题 这是test.py #! /usr/bin/env pythonimport sysprint(sys.version) 创建虚拟环境 virtualenv test2.6 -p ...

技术盛宴
17分钟前
3
0
售后服务

售后服务 买家如何申请售后服务? 1、功能路径 个人中心-我的订单-已完成-申请售后 2、操作流程 1、进入个人中心,找到订单 2、点击详情,进入订单详情页 3、点击申请售后,填写退款信息 ...

Geek-Chic
34分钟前
2
0
密码加密与微服务鉴权JWT详细使用教程

[TOC] 1.1、了解微服务状态 微服务集群中的每个服务,对外提供的都是Rest风格的接口,而Rest风格的一个最重要的规范就是:服务的无状态性。 什么是无状态? 1.服务端不保存任何客户端请求者信...

庭前云落
39分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部