首页 > Socket/ServerSocket 选项

Socket/ServerSocket 选项

Socket/ServerSocket 选项
原文:Socket/ServerSocket 选项

在网络编程中,Socket/ServerSocket有一些选项用来自定义一些行为,现在分享一下。

 

Socket选项

1.TCP_NODELAY

在Socket发送数据时,默认情况下,数据会先进入缓冲区,等缓冲区满了再发送出去,意图是为了通过减少传输数据的次数,以此来提高通信效率

但是,对于一些需要即时发送,即时响应的场景并不合适,比如网络游戏。客户端因为采用的默认行为,会等到缓冲区满了后才发送数据,服务端的响应相应也会变慢,导致整个游戏运行起来不流畅。

这时,就要开启TCP_NODELAY,关闭默认行为,实时发送实时响应。

2.SO_TIMEOUT

在读取数据时,常常因为种种原因,导致读方法阻塞,为了保证阻塞时间可控,可以设置SO_TIMEOUT选项,设置读数据时的最大等待时间,如果阻塞时间超过设置的时间,

则会抛出【Exception in thread "main" java.net.SocketTimeoutException: Read timed out】。示例如下。

客户端代码:阻塞6000ms后才发送数据

public class Main {public static void main(String[] args) throws InterruptedException, IOException {Socket socket = new Socket("127.0.0.1", 8899);System.out.println("客户端启动...");OutputStream out = socket.getOutputStream();Thread.sleep(6000); //阻塞6000ms后才发送数据out.write("This is for everyone".getBytes());}
}

服务端代码:通过SO_TIMEOUT选项,设置读阻塞时长最大为5000ms,由于客户端再6000ms后才会出数据,所以会抛出SocketTimeoutException异常。

public class SimpleServer {public static void main(String[] args) throws IOException, InterruptedException {ServerSocket serverSocket = new ServerSocket(8899, 2);System.out.println("服务端启动...");while (true) {Socket socket = serverSocket.accept();System.out.println("连接成功:" + socket);soTimeout(socket);}}private static void soTimeout(Socket socket) throws IOException {socket.setSoTimeout(5000); //设置最大阻塞时间为5000msInputStream in = socket.getInputStream();byte[] buf = new byte[1024];int len = 0;while ((len = in.read(buf)) >= 0) { //因为阻塞时间超过5000ms,所以这里抛出【Exception in thread "main" java.net.SocketTimeoutException: Read timed out】异常System.out.println("read,len=" + len + ",str=" + new String(buf, 0, len));}}
}

 

3.SO_REUSEADDR

对于Socket来说,当通过Socket.close()关闭时,底层的Socket为了把数据发送完或者接受完,不会立即关闭而是会等待一段时间,确保完成自己的使命。

但这会带来一个问题,由于Socket的端口号不能共享,一旦一个端口号被占用,之后再用这个端口号尝试建立新连接的话会报端口冲突的异常。

为了确保一个进程关闭Socket后,同一主机的其他进程还能使用这个端口,可以设置SO_REUSEADDR选项。

 

4.SO_LINGER

SO_LINGER选项用来控制Socket关闭时的行为,上面已经简单讲过,默认情况下,调用Socket.close()方法后,close()方法会立即返回,但是底层的Socket会等待数据发送完成后再关闭。

当设置Socket.setSoLinger(true, 0)选项时,close()方法也会立即返回,底层的Socket也会立即关闭,未发送完的数据会抛弃掉。

当设置Socket.setSoLinger(true, n)选项时,close()方法会阻塞,直到满足下列条件中的一个才会返回。

  1. n秒后,即使底层Socket还未发送完,也强制关闭底层Socket,并返回close()方法。

  2. 底层Socket数据全部发送完(全部送到缓冲区)。

示例如下。

服务端代码:没什么特别的,就是从Socket中读出数据,重点在客户端

public class SimpleServer {public static void main(String[] args) throws IOException, InterruptedException {ServerSocket serverSocket = new ServerSocket(8899, 2);System.out.println("服务端启动...");while (true) {Socket socket = serverSocket.accept();System.out.println("连接成功:" + socket);soLinger(socket);}}// 没什么特别的,就是从Socket中读出数据,重点在客户端private static void soLinger(Socket socket) throws InterruptedException, IOException {InputStream in = socket.getInputStream();byte[] buf = new byte[1024];int len = 0;while ((len = in.read(buf)) >= 0) {System.out.println("read,len=" + len + ",str=" + new String(buf, 0, len));}}
}

 

客户端代码:首先是不设置SO_LINGER选项,已默认的方式运行。之后#1,close()方法立即返回。#2,close()方法阻塞了4ms。

public class Main {public static void main(String[] args) throws InterruptedException, IOException {Socket socket = new Socket("127.0.0.1", 8899);//socket.setSoLinger(true, 0); #1//socket.setSoLinger(true, 10); #2System.out.println("客户端启动...");OutputStream out = socket.getOutputStream();StringBuilder sb = new StringBuilder();for (int i = 0; i < 500000; i++) {sb.append(i);}out.write(sb.toString().getBytes());long start = System.currentTimeMillis();socket.close();long end = System.currentTimeMillis();System.out.println("close:" + (end - start)); //#1:0   #2:4
    }
}

 

默认情况下,close()方法立即返回,Socket底层在发送完数据后关闭,服务端正常运行。

当把#1的注释给删掉,close()方法立即返回,Socket底层也会立即关闭,因为客户端数据没有完全发出,所以服务端运行时抛出了【Exception in thread "main" java.net.SocketException: Connection reset】异常

当吧#2的注释给删掉,close()方法阻塞了4ms才返回,Socket底层在发送完数据后关闭,服务端正常运行。

 

5.SO_RCVBUF,SO_SNDBUF

设置输入,输出缓冲区的大小。

一般情况下,对于数据量大,传输频率低的场景,适合大的缓冲区,减少传输数据的次数,提高传输效率,比如FTP、HTTP等。

对于数据量小,传输频率高,对实时性要求高的场景,适合设置小的缓冲区。

 

6.SO_KEEPALIVE

检测TCP连接的有效性。大概机制是,2小时后双方没有过交互一直处于空闲状态,则会发送一个请求,如果请求没有响应,则会认为对方已经关闭,这样本地的Socket也会自动关闭。

 

ServerSocket选项

1.SO_TIMEOUT

ServerSocket.accept()方法是个阻塞方法,会一直阻塞到有一个TCP连接成功建立,SO_TIMEOUT选项则可以设置最大的阻塞时间,超过这个时间还没有建立TCP连接的话则抛出异常。

注意和Socket的SO_TIMEOUT选项区别开,Socket的SO_TIMEOUT选项是设置读操作的最大阻塞时间,ServerSocket的SO_TIMEOUT选项是设置accep()操作的最大阻塞时间。

服务端代码:5000ms后任然没有与某个客户端成功建立连接,所以会抛出SocketTimeoutException异常。

public class SimpleServer {public static void main(String[] args) throws IOException, InterruptedException {ServerSocket serverSocket = new ServerSocket(8899, 2);serverSocket.setSoTimeout(5000); System.out.println("服务端启动...");while (true) {Socket socket = serverSocket.accept(); SO_TIMEOUT选项为5000ms,超过这段时间后,抛出【Exception in thread "main" java.net.SocketTimeoutException: Accept timed out】System.out.println("连接成功:" + socket);}}
}

 

2.SO_REUSEADDR

同Socket的SO_REUSEADDR选项类似,为了保证一个进程关闭ServerSocket后,即使它还没有释放端口,同一主机的其他进程还能使用这个端口,可以设置SO_REUSEADDR解决这个问题。

对于Socket来讲,一般Socket的端口号都是系统随机分配的,碰巧碰到同一端口的情况比较少。但是对于ServerSocket来讲,往往用的都是固定端口号,所以同一端口的情况就不能忽视了。

 

3.SO_RCVBUF

设置ServerSocket输入缓冲区的大小。

 

引用

1.《Java网络编程精解》(孙卫琴)

posted on 2019-03-11 09:26 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10508664.html

更多相关:

  • 环境: 版本:ceph 12.2.1 部署完cephfs 使用ceph-fuse挂载,并写入数据 关键参数: debug_mempool = true 将该参数置为true即可查看详细的blustore管理的内存池的数据 命令: ceph daemon osd.id dump_mempools该命令为admin_socket线程实时...

  • 在《Android网络编程》系列文章中,前面已经将Java的通信底层大致的描述了,在我们了解了TCP/IP通信族架构及其原理,接下来我们就开始来了解基于tcp/ip协议层的Socket抽象层。本篇文章将会让我们清楚的了解和学会使用Socket。 什么是Socket?它又是如何运作的?它的表现形式是什么?等等这些问题,本篇文章将逐步的揭...

  • 本文是西门子开放式TCP通信的第2篇,上一篇我们讲了使用西门子1200PLC作为TCP服务器的程序编写,可以点击下方链接阅读:【公众号dotNet工控上位机:thinger_swj】基于Socket访问西门子PLC系列教程(一)在完成上述步骤后,接下来就是编写上位机软件与PLC之间进行通信。上位机UI界面设计如下图所示:从上图可以看出...

  • 我有一个大型数据集,列出了在全国不同地区销售的竞争对手产品。我希望通过使用这些新数据帧名称中的列值的迭代过程,根据区域将该数据帧分成几个其他区域,以便我可以分别处理每个数据帧-例如根据价格对每个地区的信息进行排序,以了解每个地区的市场情况。我给出了以下数据的简化版本:Competitor Region ProductA Product...

  • 作为一名IT从业者,我来回答一下这个问题。首先,对于具有Java编程基础的人来说,学习Python的初期并不会遇到太大的障碍,但是要结合自己的发展规划来制定学习规划,尤其要重视学习方向的选择。Java与Python都是比较典型的全场景编程语言,相比于Java语言来说,当前Python语言在大数据、人工智能领域的应用更为广泛一些,而且大...

  • 这段时间通过学习相关的知识,最大的变化就是看待事物更加喜欢去了解事物后面的本质,碰到问题后解决问题思路也发生了改变。举个具体的例子,我在学习数据分析,将来会考虑从事这方面的工作,需要掌握的相关专业知识这个问题暂且按下不表,那哪些具体的问题是我需要了解的呢,以下简单罗列:1、了解数据分析师这个岗位在各个地区的需求情况?2、数据分析师的薪...

  • 这一节将开始学习python的一个核心数据分析支持库---pandas,它是python数据分析实践与实战的必备高级工具。对于使用 Python 进行数据分析来说,pandas 几乎是无人不知,无人不晓的。今天,我们就来认识认识数据分析界鼎鼎大名的 pandas。目录一. pandas主要数据结构 SeriesDataFrame二...

  • 头文件:/usr/include/getopt.h 函数传入较长参数 函数getopt_long_only和getopt_long两者用法差不多,都可以用来解析命令行选项 函数出处 #include //getopt_long()头文件位置 int getopt_long (int ___argc,...

  • 代码: [MenuItem("Tools/Test",false,1)]    static void Test()    {        Debug.Log("test");      } 注意:MenuItem中第一个参数:需要创建选项在工具栏中的路径,此路径的父目录可以是Unity中已存在的,也可以自己直接同子目录一起创建,例...