TCP编程实践小结1
说起TCP/IP协议,大家估计都能说出个一二,但是估计很少有人能够深入的理解这个协议,原因有这么几个:
- 协议本身确实复杂
- 入门教材没选对,太抽象了,导致大家浅尝辄止
- 学习过程中如果没有配合实践理解,过段时间也忘记了。
所以本篇文章的用意就是通过理论和实践的结合,加深大家对TCP协议的理解,更好的应用TCP来编写客户端和服务端。
TCP理论介绍
说到入门教材我比较推荐《图解TCP/IP》,本节内容也是在这本书的理论基础上结合自己的理解构成。
首先 TCP位于七层协议中的传输层。

TCP通信简单的说是类似这样的。

TCP协议是构建在网络层的IP协议之上的面向连接的、可靠的流协议。
TCP如何保证可靠性?
推荐使用WireShark抓包来学习TCP协议的特点,推荐一篇教程。由于HTTP协议是构建TCP协议之上的,所以可以用Wireshark对你的上网过程进行抓包,来观察TCP协议的流程和特性。
连接管理(三次握手)

上图是在HTTP GET之前,先经过了TCP的三次握手。
192.168.5.81 ——》 191.0.0.1 SYN(发起连接)
191.0.0.1 ——》 192.168.5.81 ACK(对192.168.5.81 的SYN的确认)+SYN(发起连接)
192.168.5.81 ——》 191.0.0.1 ACK(对191.0.0.1 的SYN的确认)
通过序列号与确认应答提高可靠性。

红圈部分是做个示例,TCP中的每一包数据都包含着自身的数据序列号(Sequence Number),以及已收到对方数据的确认号(Acknowledgement Number)。
以下是TCP的报文头定义,方便对照WireShark查看。

假如某包数据发送之后,迟迟未受到对方确认,则会进行超时重发。
假如重发一定次数之后,还是没有任何确认应答返回,就会判断网络或对端主机发生异常,强制关闭连接。
通过以上这个机制就可以保证数据不会存在丢包、顺序混乱的问题。
TCP以段为单位发送数据
参考Wireshark的截图,第一包数据中有个属性 MSS=1460(Maximum Segment Size最大消息长度,也就是所谓的“段”)。
以太网标准MSS是1460,同时两端的主机在发出建立连接的请求时会在TCP首部写入MSS选项,告诉对方自己的接口能够适应的MSS的大小。然后会在两者之间选择一个较小的值投入使用。
利用窗口控制提高速度 和 拥塞控制
TCP以段为单位收发数据,如果每发一个段都要进行确认的话效率有点低,于是TCP引入了窗口的概念。
窗口的大小就是指无需等待确认应答而可以继续发送数据的最大值。
在通信刚开始的时候窗口大小一般为1个段,后续随着通信的正常进行,窗口会变大,这叫做拥塞控制,主要是防止网络拥堵。因为计算机网络处在一个共享的环境中,如果大家一开始都采用最大量数据发送可能导致网络瘫痪。
下图红圈是每一个窗口确认的过程,可以看出来窗口是持续增大的。

流控制
TCP的流控制的意思就是通信双方会协商好传输数据的速度,否则一方数据发送太快,另一方数据处理能力有限就会导致数据丢弃,从而造成流量的浪费。
接收主机将自己可以接受的缓冲区大小放入到TCP首部字段通知给发送端。这个字段越大,说明网络的吞吐量越大。
OK,以上是TCP的一些基本概念和特性,讲的比较浅,算是自己的一个总结,说多了也不容易记住。
本篇文章先到这里,下一篇再介绍Socket API及其相关使用问题。
TCP编程实践小结1的更多相关文章
- Socket编程实践(6) --TCP服务端注意事项
僵尸进程处理 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中添加 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法,解决僵尸进程 sign ...
- C# socket编程实践
C# socket编程实践——支持广播的简单socket服务器 在上篇博客简单理解socket写完之后我就希望写出一个websocket的服务器了,但是一路困难重重,还是从基础开始吧,先搞定C# ...
- [Python] 网络编程之TCP编程
转自:TCP编程 - 廖雪峰的官方网站 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协 ...
- 牛客网Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤
福利 => 每天都推送 欢迎大家,关注微信扫码并加入我的4个微信公众号: 大数据躺过的坑 Java从入门到架构师 人工智能躺过的坑 Java全栈大联盟 ...
- Socket编程实践(6) --TCPNotes服务器
僵尸进程过程 1)通过忽略SIGCHLD信号,避免僵尸进程 在server端代码中加入 signal(SIGCHLD, SIG_IGN); 2)通过wait/waitpid方法.解决僵尸进程 sign ...
- 高性能javascript学习笔记系列(5) -快速响应的用户界面和编程实践
参考高性能javascript 理解浏览器UI线程 用于执行javascript和更新用户界面的进程通常被称为浏览器UI线程 UI线程的工作机制可以理解为一个简单的队列系统,队列中的任务按顺序执行 ...
- 高性能JavaScript 编程实践
前言 最近在翻<高性能JavaScript>这本书(2010年版 丁琛译),感觉可能是因为浏览器引擎的改进或是其他原因,书中有些原本能提高性能的代码在最新的浏览器中已经失效.但是有些章节的 ...
- Java TCP编程
Java编写TCP编程--回射信息实例 注:简单的tcp联系,还存在问题,readUTF()为阻塞型,如果之前的用户一直不输入,则一直阻塞,之后的用户再连接会出现问题. import java.io. ...
- Method Swizzling和AOP(面向切面编程)实践
Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...
随机推荐
- linux下部署monogoDB服务(以及安装php mogodb扩展)
这两天网站转移到新的服务器后,登录时出现一个问题,会等待几分钟服务器才响应. 开始以为是nginx服务器的问题,后面经过排查发现是php一个登陆验证的函数的问题,每次跑到这个函数就会迟钝几分钟. 经过 ...
- Java 日志体系
Java 日志体系 <java 日志和 SLF4J 随想>:http://ifeve.com/java-slf4j-think/ 一.常用的日志组件 名称 jar 描述 log4j log ...
- C#实现局部峰值查找,功能对应Matlab中的findpeaks.m(转)
相关算法的原理参考Ronny,地址:图像分析:投影曲线的波峰查找,这里感谢下原作者. 参照C++的代码实现,我用C#翻译了下,其实原理也很简单的,下面放相关实现代码: private double[] ...
- SpringMVC 学习 十一 springMVC控制器向jsp或者别的控制器传递参数的四种方法
以后的开发,大部分是发送ajax,因此这四种传递参数的方法,并不太常用.作为了解吧 第一种:使用原生 Servlet 在控制器的响应的方法中添加Servlet中的一些作用域:HttpRequestSe ...
- __LINE__的用法
简单的说,__LINE__可以获取当前代码的函数,结合__FUNCTION__可以打印调试信息,比如函数出错时运行的函数名,及行号,例如 #define p_err_fun , os_time_get ...
- 《pyhton语言程序设计》_第一章笔记
章1.62 (1).python区分大小写. (2).python忽略在符号#之后的同行的内容 (3).python和matlab很相似(个人感觉) (4).章节1.91: >>>i ...
- 长方体类Java编程题
1. 编程创建一个Box类(长方体),在Box类中定义三个变量,分别表示长方体的长(length).宽(width)和高(heigth),再定义一个方法void setBox(int l, int w ...
- Shell 中字符串变量的赋值注意点
1. 变量赋值 语法:var="saaaa" PS: 等号两边不能有空格 2. 脚本示例如下: #!/bin/sh # Get bug activity info # usage ...
- WeexSDK源码分析(iOS)
0.从工作原理谈起 Weex 表面上是一个客户端技术,但实际上它串联起了从本地开发.云端部署到分发的整个链路.开发者首先可在本地像编写 web 页面一样编写一个 app 的界面,然后通过命令行工具将之 ...
- Mac键盘按键符号
通过修饰键来查看 像command.option.control.shift这些按键在Mac下叫做修饰键,一般情况下他们大都用来辅助输入或者用作快捷键的修饰键. 打开“系统偏好设置”,点击“键盘→键盘 ...