Internet上,数据按有限大小的包传输,这些包成为数据报(datagram),每个数据报包含一个首部(header)和一个有效载荷(payload)。首部包含包发送到的地址和端口、包来自的地址和端口、检测数据是否被破坏的校验和,以及用于保证可靠传输的各种其他管理信息。

有效载荷包含数据本身。

不过,由于数据报长度有限,通常必须将数据分解为多个包,再在目的地重新组合。也有可能一个包或多个包在传输中丢失或遭到破坏,需要重传。或者包乱序到达,需要重新排序。所有这些(将数据分解为包、生成首部、解析入站包的首部、跟踪哪些包已经收到而哪些没有收到等)是很繁重的工作,需要大量复杂的代码。

Socket帮你掩盖了这些底层细节,如错误检测、包大小、包分解、包重传、网络地址等。Socket允许程序员将网络连接看作是另外一个可以读写字节的流。

Socket是两台主机之间的一个连接,它可以完成7个基本操作:
1)连接远程主机
2)发送数据
3)接收数据
4)关闭连接
5)绑定端口
6)监听入站数据
7)在绑定端口上接受来自远程机器的连接

一旦建立了socket连接,就可以使用输入输出流,这个连接是全双工的(full-duplex),两台主机都可以同时发送和接收数据。

SMTP是服务器之间或邮件客户端与服务器之间传输电子邮件所用的协议。

半关闭Socket:close方法同时关闭Socket的输入流和输出流,如果只希望关闭连接的一半(输入/输出),调用shutdownInput或shutdownOutput方法即可。这两个方法并不关闭Scoket,实际上,它会调整与Socket连接的流,使它认为已经到了流的末尾。关闭输入之后,再读取输入流会返回-1,关闭输出流之后再写入Socket则会抛出一个IOException异常。
即使半关闭了连接,或者将连接的两半都关闭了,使用结束后还是需要关闭该Socket。shutdown只是影响了socket流,并不释放与socket关联的资源,如占用的端口等。

java.net.Socket是Java完成客户端TCP操作的基础类,它使用原生代码与主机操作系统的本地TCP栈进行通信。

public Socket(String host, int port) throws UnknownHostException, IOException
public Socket(InetAddress host, int port) throws IOException

这两个构造函数,在返回之前会与远程主机建立一个活动的网络连接。port在1~65535之间。

public Socket()
public Socket(Proxy proxy)
protected Socket(SocketImpl impl)
这三个函数可以创建未连接的Socket。

public Socket(String host, int port, InetAddress interface, int localPort)

  throws IOException, UnknownHostException

public Socket(InetAddress host, int port, InetAddress interface, int localPort)

  throws IOException

这两个构造函数可以用来指定从哪个接口和端口连接。

SocketAddress

SocketAddress表示一个连接端点,理论上可以用于TCP和非TCP socket。实际上只支持TCP/IP Socket。

SocketAddress主要是为了暂时的socket连接信息(如IP地址和端口)提供一个方便的存储,即使最初的socket已断开并被垃圾回收,这些信息也可以重用来创建新的Socket。

boolean connected = socket.isConnected() && ! socket.isClosed();

isConnected表示是否连接过一个远程主机,即使socket已经关闭,因而要判断socket是否打开着的,还要判断是否已经关闭了。

Socket选项

1)TCP_NODELAY

设置为true,可确保包会尽可能快地发送,而不论包的大小。
正常情况下,小数据包在发送前会组合为更大的包,在发送另一个包之前,本地主机要等待远程系统对前一个包的确认,这称为Nagle算法。

Nagle算法的问题是如果远程系统没有足够快地将确认发送回本地系统,那么依赖于小数据量信息稳定传输的应用程序会变慢。对于网络或游戏等计算机应用程序(服务器需要实时跟踪客户端鼠标的移动),这个问题尤为严重,在一个相当慢的网络中,即使简单地打字也会由于持续的缓冲而变得太慢。设置为true,可以关闭这种缓冲模式,这样素有包一旦就绪就会发送。

2)SO_LINGER

指定了Socket关闭时如何处理尚未发送的数据报,默认情况下,close方法将立即返回,但系统仍然会尝试发送剩余的数据,如果延迟时间设置为0,那么当Socket关闭时,所有未发送的数据包都将被丢弃,如果SO_LINGER打开而且延迟时间设置为任意正数,close方法会阻塞指定的时间,等待发送数据和接收确认。指定时间一过,Socket关闭,所有剩余的数据都不会发送,也不会接收确认。
返回-1表示该选项被禁用,会根据需要用更多的时间发送剩余的数据。

3)SO_TIMEOUT

正常情况下,尝试从Socket读取数据时,read()调用会阻塞尽可能长的时间来得到足够的字节。设置timeout确保这个调用会阻塞的时间不会超过指定的阈值,如果超出则抛异常,但是Socket仍然是连接的,可以再次尝试肚饿去这个Socket,下一次调用可能会成功。
0表示无限超时。

4)SO_RCVBUF和SO_SNDBUF

TCP使用缓冲区来提升网络性能,较大的缓冲区会提升快速连接(比如10M/s)的性能,而较慢的拨号连接利用较小的缓冲区会有更好地表现。

一般来讲,传输连续的大数据块时(在ftp和http中较为常见),可以从大缓冲区收益,而对于交互式会话的小数据量传输(比如telnet和很多游戏),大缓冲区则没有多大帮助。如今128K字节已经是一个常见的默认设置。

可以达到的最大带宽=缓冲区大小/延迟。例如,xp上,假设两个主机之间的延迟为500ms,xp上的缓冲区大小为17520字节,则带宽=17520/0.5=273.75kb/s。这是Socket的最大速度,而不论网络速度有多快。对于一个拨号连接来说,这样的速度已经很快了。

可以通过减少延迟来提升速度,不过,延迟与网络硬件有关,另外还取决于你的应用控制之外的其他一些因素。
如果把缓冲区从17520字节提升到128K,则最大带宽会增加到2Mb/s,如果加到256K时,最大带宽会增大到4Mb/s。

当然网络本身对最大带宽也是有限制的,如果将缓冲区设置的过高,程序会试图以过高的速度发送和接收数据,而网络来不及处理,这就会导致拥塞、丢包和性能下降。因此,要得到最大带宽,需要让缓冲区大小与连接的延迟匹配,是它稍小于网络的带宽。

可以用ping去检测主机的延迟。

SO_RCVBUF控制用于网络输入的建议的接收缓冲区的大小,虽然可以独立地设置接收和发送缓冲区的大小,但是实际上缓冲区通常会设置为二者中较小的一个。

Linux系统通常指定一个最大缓冲区大小,一般是64KB或256KB,而且不允许任何socket有更大的缓冲区。

一般情况下,如果你发送你的应用不能充分利用可用带宽(例如,你有一个25Mb/s的Internet连接,但是数据传输速率仅为1.5Mb/s),那么可以试着增加缓冲区的大小;相反,如果存在丢包和拥塞现象,则要减少缓冲区大小。

不过,大部分情况,除非网络在某个方向上负载过大,否则默认值就很合适。具体来说,现代操作系统使用TCP窗口缩放来动态调整缓冲区的大小,以适应网络。

一般经验是,除非你检测到某个问题,否则不要进行调整。一般调整操作系统的最大缓冲区比在Java里头调整单个socket的缓冲区大小效益要高。

5)SO_KEEPALIVE

如果打开这个,客户端偶尔会通过一个空闲连接发送一个数据包(一般两小时一次),以确保服务器没有崩溃。如果服务器没能响应这个包,客户端会持续尝试11分钟多的时间,直到接收到响应为止。如果在12分钟内未收到响应,则客户端就关闭socket。如果不打开这个,不活动的客户端可能会永远存在下去,而不会注意到服务器是否已经崩溃。

6)OOBINLINE

TCP包括一个可以发送单字节带外(Out Of Band,OOB)紧急数据的特性。这个数据会立即发送,此外,当接收方收到紧急数据时会得到通知,在处理其他已收到的数据之前可以选择先处理这个紧急数据(必要时flush当前缓冲区)。

Java里对应的方法是sendUrgentData

默认情况下,Java会忽略从Socket接收的紧急数据,如果希望接收到正常数据中的紧急数据,需要setOOBInline为true。一旦开启,到达的任何紧急数据将以正常方式放在Socket的输入流中等待读取。

7)SO_REUSEADDR

一个Socket关闭时,可能不会立即释放本地端口,尤其是当Socket关闭时若仍有一个打开的连接,就不会释放本地端口,有时会等待一小段时间,确保接收到所有要发送到这个端口的延迟数据包,Socket关闭时这些数据包可能仍在网络上传输,系统不会对接收到的延迟包做任何处理,只是希望确保这些数据不会意外地传入绑定到同一端口的新进程。

如果使用随机端口,则问题不大,但是如果Socket绑定到一个已知的端口,可能会有问题,因为这会阻止所有其他Socket同时使用这个端口,如果开启这个参数(默认是关闭),则允许另外一个Socket绑定到这个端口,即使此时仍有可能存在前一个Socket未接收的数据。

setReuseAddress必须在绑定新Socket之前调用。只有之前连接的Socket和重用老地址的新Scoket的这个值都设置为true,才能生效。

8)IP_TOS

不同类型的Internet服务对性能有不同的需求,比如视频要求相对较高的带宽和较短的延迟,而email可以通过较低带宽的连接传递等。
服务类型存储在IP首部中的一个名为IP_TOS的8位字段中。在Java中使用setTrafficClass来设定,java里头是0-255,但是TCP首部要求是8位,因而只能使用int的低字节。

Socket异常
1)BindException,端口被占用或没有权限使用该端口
2)ConnectException,连接远程主机被拒绝(远程主机忙或者没有进程监听该端口)
3)NoRouteToHostException,连接超时
4)ProtocolException,违反TCP/IP规定

Java必知必会之socket相关推荐

  1. Java架构师必知必会,带走不谢

    可以说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,掌握了Java技术体系,不管在成熟的大公司,快速发展的公司,还是创业阶段的公司,都能有立足之地. 成为Java架构师,需要掌握哪些技能呢 ...

  2. java面试必知必会

    java面试必知必会 面向对象 成员变量成员方法 Integer相关 double 和 Double相关 多态,向上转型 hashcode.==.equals比较 java中子类继承父类时是否继承构造 ...

  3. java的标量和聚合量_第5节:Java基础 - 必知必会(下)

    第5节:Java基础 - 必知必会(下) 本小节是Java基础篇章的第三小节,主要讲述Java中的Exception与Error,JIT编译器以及值传递与引用传递的知识点. 一.Java中的Excep ...

  4. 必知必会系列-JAVA虚拟机原理

    系列文章 必知必会系列-Spring技术原理 必知必会系列-JAVA虚拟机原理 必知必会系列-Redis技术原理 引言 随着技术的不断演进,在不同时间阶段都会有不同的技术产物,那么如何快速的学习和掌握 ...

  5. Java XxlJob 必知必会<续篇>

    通过 Java  XxlJob 必知必会 这篇文章的学习,我们大致知道了 xxljob 是做什么的,今天这篇文章我们将继续研究一下 xxljob 的其他使用场景. Step1: 创建一个运行模式为 P ...

  6. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    为什么80%的码农都做不了架构师?>>>    本文原作者:"竹千代",原文由"玉刚说"写作平台提供写作赞助,原文版权归"玉刚说&q ...

  7. c2064 项不会计算为接受0个参数的函数_【JS必知必会】高阶函数详解与实战

    本文涵盖 前言 高级函数概念 函数作为参数的高阶函数 map filter reduce sort详解与实战 函数作为返回值的高阶函数 isType函数与add求和函数 如何自己创建高阶函数 前言 一 ...

  8. SpringBoot入门到精通_第6篇 _必知必会

    接上一篇:SpringBoot入门到精通_第5篇 _SpringBoot Actuator监控 https://blog.csdn.net/weixin_40816738/article/detail ...

  9. 《MySQL必知必会》.pdf

    什么是数据库? 数据库是大量数据的集合,通常以电子形式进行数据存储. 数据库的设计通常是为了使其易于存储和访问信息.数据库的使用对任何公司或组织都至关重要,这是因为数据库存储了有关公司的所有相关详细信 ...

  10. 分享一个开源的项目,数据结构和算法必知必会的50个代码实现

    数据结构和算法必知必会的50个代码实现 这个开源项目是有前Google工程师打造出来的,使用了c,go,java,python,php等很多中语言实现了一些数据结构和算法,对于喜欢算法的来说可谓是一个 ...

最新文章

  1. Ubuntu 15.10安装ns2.35+nam
  2. XCode6报数组越界错误的问题
  3. 九月腾讯,创新工场,淘宝等公司最新面试三十题(更新至10.04)
  4. Kindeditor JS 取值。。。
  5. Python标准库shutil中rmtree()使用回调函数
  6. 定义空列表元素类型_python数据类型是什么
  7. iOS——使用StroryBoard页面跳转及传值
  8. 持久层和数据访问层_什么是持久层? JDBC 演变的 Mybatis 架构分析
  9. matlab傅里叶变换处理图像,MATLAB数字图像处理(1)基本操作和傅里叶变换
  10. html网页怎么分页打印,web如何实现页面分页打印
  11. 读《产品经理面试宝典》
  12. pdf如何转化成word文档?
  13. PowerDNS Authoritative Server 3.2 RC3 发布
  14. Linpack安装、配置与运行
  15. 斗破苍穹-牛仔版美杜莎
  16. games101 作业4
  17. Cyber_monitor的使用
  18. ORA-20005: object statistics are locked (stattype = ALL)-转
  19. Word 2016 如何设置黑底白字
  20. Google宣布收购摩托罗拉移动

热门文章

  1. 【Prison Break】第二天(3.28)
  2. 16位伪指令汇编程序查看内存
  3. C#的目录与文件操作
  4. 网易编程题——牛牛的闹钟
  5. CryoSat-2数据下载
  6. 机器学习笔记0_学习资料整理
  7. python 计算相关系数和决定系数
  8. HTML学习总结(1)——HTML基本介绍
  9. matlab中pdist,pdist用法
  10. 为什么大家都说 SELECT * 效率低