本文是学习java Socket整理的资料,供参考。

1       Socket通信原理

1.1     ISO七层模型

1.2     TCP/IP五层模型

应用层相当于OSI中的会话层,表示层,应用层。

区别参考:http://blog.chinaunix.net/uid-22166872-id-3716751.html

1.3     TCP报文

(1)序号:Seq序号,占32位,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记。

(2)确认序号:Ack序号,占32位,只有ACK标志位为1时,确认序号字段才有效,Ack=Seq+1。

(3)标志位:共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:

(A)URG:紧急指针(urgent pointer)有效。

(B)ACK:确认序号有效。

(C)PSH:接收方应该尽快将这个报文交给应用层。

(D)RST:重置连接。

(E)SYN:发起一个新连接。

(F)FIN:释放一个连接。

需要注意的是:

(A)不要将确认序号Ack与标志位中的ACK搞混了。

(B)确认方Ack=发起方Req+1,两端配对。

1.4     Socket通信

Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

1.5     三次握手

Socket连接建立和关闭,详见:http://www.2cto.com/net/201310/251896.html

2       通信基本概念

2.1     短连接

连接->传输数据->关闭连接

短连接是指SOCKET连接,发送数据,接收数据后,马上断开连接。

比如:

HTTP1.0默认是短连接,无状态的,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。 、

Http1.1默认是长连接

无状态:协议对于事务处理没有记忆能力;

2.2     长连接

连接->传输数据->保持连接 -> 传输数据-> 。。。 ->关闭连接。

建立SOCKET连接后,不管是否使用,一致保持连接。

2.3     半包

接受方没有接受到一个完整的包,只接受了部分;

原因:TCP为提高传输效率,将一个包分配的足够大,导致接受方并不能一次接受完。

影响:长连接和短连接中都会出现

2.4     粘包

发送方发送的多个包数据到接收方接收时粘成一个包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

分类:一种是粘在一起的包都是完整的数据包,另一种情况是粘在一起的包有不完整的包

出现粘包现象的原因是多方面的:

1)发送方粘包:由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。

2)接收方粘包:接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。

2.5     分包

分包(1):在出现粘包的时候,我们的接收方要进行分包处理;

分包(2):一个数据包被分成了多次接收;

原因:1. IP分片传输导致的;2.传输过程中丢失部分包导致出现的半包;3.一个包可能被分成了两次传输,在取数据的时候,先取到了一部分(还可能与接收的缓冲区大小有关系)。

影响:粘包和分包在长连接中都会出现

2.6     如何解决半包,粘包问题

出现粘包和半包现象,是因为TCP当中,只有流的概念,没有包的概念。

UDP不会出现半包,粘包情况,原因是UDP是一个完整的数据包,发送时不进行合并,因此接收的时候就不存在粘包情况。

固定长度:每次发送固定长度的数据;

特殊标示:以回车,换行作为特殊标示;获取到指定的标识时,说明包获取完整。

字节长度:包头+包长+包体的协议形式,当服务器端获取到指定的包长时才说明获取完整;

参考文章(有图):http://blog.csdn.net/pi9nc/article/details/17165171

2.7     什么时候需要考虑粘包的情况

短连接:不用考虑粘包的情况;

发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储,也不用考虑粘包;

长连接:需要在连接后一段时间内发送不同结构数据;

处理方式:接收方创建一预处理线程,对接收到的数据包进行预处理,将粘连的包分开;

2.8     TCP与UDP的差别

  • 基于连接与无连接;
  • 对系统资源的要求(TCP较多,UDP少);
  • UDP程序结构较简单;
  • 流模式与数据报模式 ;
  • TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。
  • 网络分化:机器本身是好的,但是之间的通信出现问题;
  • 网络抖动:网络中的延迟是指信息从发送到接收经过的延迟时间,一般由传输延迟及处理延迟组成;而抖动是指最大延迟与最小延迟的时间差,如最大延迟是20毫秒,最小延迟为5毫秒,那么网络抖动就是15毫秒,它主要标识一个网络的稳定性。

2.9     其他通信问题

2.10         参考资料

一个包没有固定长度,以太网限制在46-1500字节,1500就是以太网的MTU,超过这个量,TCP会为IP数据报设置偏移量进行分片传输,现在一般可允许应用层设置8k(NTFS系)的缓冲区,8k的数据由底层分片,而应用看来只是一次发送。

对于UDP,就不要太大,一般在1024至10K。注意一点,你无论发多大的包,IP层和链路层都会把你的包进行分片发送,一般局域网就是1500左右,广域网就只有几十字节。分片后的包将经过不同的路由到达接收方,对于UDP而言,要是其中一个分片丢失,那么接收方的IP层将把整个发送包丢弃,这就形成丢包。

TCP作为流,发包是不会整包到达的,而是源源不断的到,那接收方就必须组包。而UDP作为消息或数据报,它一定是整包到达接收方。

关于接收,一般的发包都有包边界,首要的就是你这个包的长度要让接收方知道,于是就有个包头信息,对于TCP,接收方先收这个包头信息,然后再收包数据。一次收齐整个包也可以,可要对结果是否收齐进行验证。这也就完成了组包过程。UDP,那你只能整包接收了。要是你提供的接收Buffer过小,TCP将返回实际接收的长度,余下的还可以收,而UDP不同的是,余下的数据被丢弃并返回WSAEMSGSIZE错误。注意TCP,要是你提供的Buffer佷大,那么可能收到的就是多个发包,你必须分离它们,还有就是当Buffer太小,而一次收不完Socket内部的数据,那么Socket接收事件(OnReceive),可能不会再触发,使用事件方式进行接收时。

3       Socket实例

3.1     Socket通信模型

3.2     Socket架构完整模型

  • 解决半包,粘包(编解码)
  • 服务端支持多线程
  • 支持心跳检测
  • 指定端口实例化一个SeverSocket
  • 调用ServerSocket的accept()方法,以在等待连接期间造成阻塞
  • 获取位于该底层的Socket的流以进行读写操作
  • 将数据封装成流
  • 对Socket进行读写
  • 关闭打开的流

3.3     服务端开发

//建立ServerSocket对象,监听绑定端口

ServerSocket server=new ServerSocket(1000);

//建立接收Socket,阻塞响应

Socket client=server.accept();

//获得输入流,用于接收客户端信息

InputStream in=server.getInputStream();

//获得输出流,用于输出客户端信息

//对输入流进行包装,方便使用

BufferedReader inRead=new BufferedReader(new InputStreamReader(in));

//对输出流进行包装,方便使用

PrintWriter outWriter=new PrintWriter(out);

while(true)

{

String str=inRead.readLine();//读入

outWriter.println("输出到客户端");

outWriter.flush();//输出

if(str.equals("end"))

{

break;

}

}

//关闭Socket

client.close();

server.close();

3.4     客户端开发

  • 通过IP地址和端口实例化Socket,请求连接服务器
  • 获得Socket上的流以进行读写
  • 把流封装进BufferedReader/PrintWriter的实例
  • 对Socket进行读写
  • 关闭打开的流

//使用Socket,建立与服务端的连接

Socket client=new Socket("127.0.0.1",1000);

InputStream in=client.getInputStream();//获得输入流

OutputStream out=client.getOutputStream();//获得输出流

//包装输入流,输出流

BufferedReader inRead=new BufferedReader(new InputStreamReader(in));

PrintWriter outWriter=new PrintWriter(out);

//获得控制台输入

BufferedReader inConsole=new BufferedReader(new InputStreamReader(in));

while(true)

{

String str=inConsole.readLine();//读取控制台输入

outWriter.println(str);//输出到服务端

outWriter.flush();//刷新缓冲区

if(str.equals("end"))

{

break;

}//退出

System.out.println(inRead.readLine())//读取服务端输出

}

client.close();

DOS下运行客户端

java -classpath sockettest-0.0.1-SNAPSHOT.jar cn.com.gome.sockettest.basic.ClientTest

3.5     多线程服务端

3.6     心跳检测

方法1:socket.sendUrgentData(0);//发送1个字节的紧急数据,默认情况下,服务器端没有开启紧急数据处理,不影响正常通信

try{
      socket.sendUrgentData(0xFF);
}catch(Exception ex){
      reconnect();
}

只要对方Socket的SO_OOBINLINE属性没有打开,就会自动舍弃这个字节,而SO_OOBINLINE属性默认情况下就是关闭的。

方法2:自定义心跳字符串

3.7     各类数据读写

传输字节,字符,对象【ObjectInputStream ObjectOutputStream】(实例)

JAVA通信系列一:Java Socket技术总结的更多相关文章

  1. 【java多线程系列】java内存模型与指令重排序

    在多线程编程中,需要处理两个最核心的问题,线程之间如何通信及线程之间如何同步,线程之间通信指的是线程之间通过何种机制交换信息,同步指的是如何控制不同线程之间操作发生的相对顺序.很多读者可能会说这还不简 ...

  2. 【java虚拟机系列】java虚拟机系列之JVM总述

    我们知道java之所以能够快速崛起一个重要的原因就是其跨平台性,而跨平台就是通过java虚拟机来完成的,java虚拟机属于java底层的知识范畴,即使你不了解也不会影响绝大部分人从事的java应用层的 ...

  3. Java Web系列:Java Web 项目基础

    1.Java Web 模块结构 JSP文件和AXPX文件类似,路径和URL一一对应,都会被动态编译为单独class.Java Web和ASP.NET的核心是分别是Servlet和IHttpHandle ...

  4. java并发系列(六)-----Java并发:volatile关键字解析

    在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保证可见性 ...

  5. 【java开发系列】—— java输入输出流

    前言 任何语言输入输出流都是很重要的部分,比如从一个文件读入内容,进行分析,或者输出到另一个文件等等,都需要文件流的操作.这里简单介绍下reader,wirter,inputstream,output ...

  6. Java多线程系列一——Java实现线程方法

    Java实现线程的两种方法 继承Thread类 实现Runnable接口 它们之间的区别如下: 1)Java的类为单继承,但可以实现多个接口,因此Runnable可能在某些场景比Thread更适用2) ...

  7. 【Java并发系列】--Java内存模型

    Java内存模型 1 基本概念 程序:代码,完成某一个任务的代码序列(静态概念) 进程:程序在某些数据上的一次运行(动态) 线程:一个进程有一个或多个线程组成(占有资源的独立单元) 2 JVM与线程 ...

  8. java并发系列(八)-----java异步编程

    同步计算与异步计算 从多个任务的角度来看,任务是可以串行执行的,也可以是并发执行的.从单个任务的角度来看,任务的执行方式可以是同步的,也可以是异步的. Runnable.Callable.Future ...

  9. 转:Java NIO系列教程(七) Socket Channel

    Java NIO中的SocketChannel是一个连接到TCP网络套接字的通道.可以通过以下2种方式创建SocketChannel: 打开一个SocketChannel并连接到互联网上的某台服务器. ...

随机推荐

  1. Git 子模块 - submodule

    有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目. 也许是第三方库,或者你 独立开发的,用于多个父项目的库. 现在问题来了:你想要把它们当做两个独立的项目,同时又想在 一个项目中使用另 ...

  2. 一起学微软Power BI系列-使用技巧(4)Power BI中国版企业环境搭建和帐号问题

    千呼万唤的Power BI中国版终于落地了,相信12月初的微软技术大会之后已经铺天盖地的新闻出现了,不错,Power BI中国版真的来了,但还有些遗憾,国际版的一些重量级服务如power bi emb ...

  3. 【大型网站技术实践】初级篇:借助Nginx搭建反向代理服务器

    一.反向代理:Web服务器的“经纪人” 1.1 反向代理初印象 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从 ...

  4. app开发外包注意事项,2017最新资讯

    我们见过很多创业者,栽在这app外包上.很多创业者对于app外包这件事情不是特别重视,以为将事情交给app外包公司就完事了,实际上不是的.无论是从选择app外包公司还是签订合同.售后维护等各方面都有许 ...

  5. iOS开发之ReactiveCocoa下的MVVM(干货分享)

    最近工作比较忙,但还是出来更新博客了,今天给大家分享一些ReactiveCocoa以及MVVM的一些东西,干活还是比较足的.在之前发表过一篇博文,名字叫做<iOS开发之浅谈MVVM的架构设计与团 ...

  6. 当web.config文件放置在共享目录下(UNC),启动IIS会提示有错误信息500.19,伴随有错误代码0x80070003和错误代码0x80070005的解决办法

    最近遇到一个很有意思的使用环境,操作人员将所有的网站应用内容投放到共享存储里面,并且使用微软的SMB协议将其以CIFS的方式共享出来,使用Windows Server 2008 R2的IIS将其连接起 ...

  7. keepalived从机接管后主机恢复不抢占VIP

    在lvs+keepalived环境中,为了减小keepalived主从切换带来的意外风险,,设置主机恢复后不抢占VIP.待进行vrrp协议通告备机不可用时切换.主要修改两个地方.(红色部分) 只需修改 ...

  8. 《月之猎人 (Moon Hunters)》主角设计

    原文链接 游戏开发人员,你们好! 我是 Kitfox Games 工作室的总监 Tanya,我们的工作室位于加拿大的蒙特利尔,拥有六名员工. 我们 3 月份发布了<月之猎人>游戏的桌面版, ...

  9. RTP与RTCP协议介绍(转载)

    RTSP发起/终结流媒体.RTP传输流媒体数据 .RTCP对RTP进行控制,同步.RTP中没有连接的概念,本身并不能为按序传输数据包提供可靠的保证,也不提供流量控制和拥塞控制,这些都由RTCP来负责完 ...

  10. Spring Security OAuth2 开发指南

    官方原文:http://projects.spring.io/spring-security-oauth/docs/oauth2.html 翻译及修改补充:Alex Liao. 转载请注明来源:htt ...