TCP/UDP协议、理解三次握手四次挥手、Socket
一、什么是socket?
中文名叫套接字,是对底层的 TCP IP UDP 等网络协议进行封装,使得上层的应用程序开发者,不用直接接触这对复杂,丑陋的协议。
在程序员的言论,他就是一个封装好的模块,要完成网络通讯,只需要使用系统提供的socket模块就行,我们通过调用模块中已经实现的方法建立两个进程之间的
连接和通信。
了解socket层:
二、套接字的发展史
套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。
基于文件类型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族的名字:AF_INET
(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET
三、TCP和UDP协议
TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序
UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)
conclusion:
TCP和UDP是传输层最常见的协议,主要控制传输数据的方式。
TCP:
优点:通过三次握手来与服务器建立连接,可以保证数据的完整性。
a机器给b机器发送数据包 要求b机器必须立即返回一个确认包
a机器会等待一段时间,如果超时还没有收到确认,则重发数据
缺点:传输效率低
使用场景: 文字聊天,支付宝转账等,
UDP:
传输方式:不需要建立连接,直接发送
缺点: 不能保证数据的完整性
优点:传输效率比TCP高
使用场景:视频通话,语音通话,UDP
python中的socket,在使用socket的时候用户需要关心的是 ip地址,port端口, 传输协议TCP/UDP,你要发送的数据data,在写网络编程的时候,必然是有两台代码, 对应着客户端和服务器,使用socket来完成TCP通讯,应该先完成服务器的代码编写。
重点理解TCP协议中三次握手、四次握手的概念:
当应用程序希望通过 TCP 与另一个应用程序通信时,它会发送一个通信请求。这个请求必须被送到一个确切的地址。在双方“握手”之后,TCP 将在两个应用程序之间建立一个全双工 (full-duplex) 的通信。这个全双工的通信将占用两个计算机之间的通信线路,直到它被一方或双方关闭为止。
三次握手示意图:
step1:第一次握手
建立连接时,客户端发送SYN包到服务器,其中包含客户端的初始序号seq=x,并进入SYN_SENT状态,等待服务器确认。(其中,SYN=1,ACK=0,表示这是一个TCP连接请求数据报文;序号seq=x,表明传输数据时的第一个数据字节的序号是x)。
step2:第二次握手
服务器收到请求后,必须确认客户的数据包。同时自己也发送一个SYN包,即SYN+ACK包,此时服务器进入SYN_RECV状态。(其中确认报文段中,标识位SYN=1,ACK=1,表示这是一个TCP连接响应数据报文,并含服务端的初始序号seq(服务器)=y,以及服务器对客户端初始序号的确认号ack(服务器)=seq(客户端)+1=x+1)。
step3:第三次握手
客户端收到服务器的SYN+ACK包,向服务器发送一个序列号(seq=x+1),确认号为ack(客户端)=y+1,此包发送完毕,客户端和服务器进入ESTAB_LISHED(TCP连接成功)状态,完成三次握手。
为什么需要三次握手,两次不可以吗?或者四次、五次可以吗?
我们来分析一种特殊情况,假设客户端请求建立连接,发给服务器SYN包等待服务器确认,服务器收到确认后,如果是两次握手,假设服务器给客户端在第二次握手时发送数据,数据从服务器发出,服务器认为连接已经建立,但在发送数据的过程中数据丢失,客户端认为连接没有建立,会进行重传。假设每次发送的数据一直在丢失,客户端一直SYN,服务器就会产生多个无效连接,占用资源,这个时候服务器可能会挂掉。这个现象就是我们听过的“SYN的洪水攻击”。
conclusion:
第三次握手是为了防止:如果客户端迟迟没有收到服务器返回确认报文,这时会放弃连接,重新启动一条连接请求,但问题是:服务器不知道客户端没有收到,所以他会收到两个连接,浪费连接开销。如果每次都是这样,就会浪费多个连接开销。
四次挥手示意图:
step1:第一次挥手
首先,客户端发送一个FIN,用来关闭客户端到服务器的数据传送,然后等待服务器的确认。其中终止标志位FIN=1,序列号seq=u。
step2:第二次挥手
服务器收到这个FIN,它发送一个ACK,确认ack为收到的序号加一。
step3:第三次挥手
关闭服务器到客户端的连接,发送一个FIN给客户端。
step4:第四次挥手
客户端收到FIN后,并发回一个ACK报文确认,并将确认序号seq设置为收到序号加一。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。
客户端发送FIN后,进入终止等待状态,服务器收到客户端连接释放报文段后,就立即给客户端发送确认,服务器就进入CLOSE_WAIT状态,此时TCP服务器进程就通知高层应用进程,因而从客户端到服务器的连接就释放了。此时是“半关闭状态”,即客户端不可以发送给服务器,服务器可以发送给客户端。
此时,如果服务器没有数据报发送给客户端,其应用程序就通知TCP释放连接,然后发送给客户端连接释放数据报,并等待确认。客户端发送确认后,进入TIME_WAIT状态,但是此时TCP连接还没有释放,然后经过等待计时器设置的2MSL后,才进入到CLOSE状态。
为什么需要2MSL时间?
首先,MSL即Maximum Segment Lifetime,就是最大报文生存时间,是任何报文在网络上的存在的最长时间,超过这个时间报文将被丢弃。《TCP/IP详解》中是这样描述的:MSL是任何报文段被丢弃前在网络内的最长时间。RFC 793中规定MSL为2分钟,实际应用中常用的是30秒、1分钟、2分钟等。
TCP的TIME_WAIT需要等待2MSL,当TCP的一端发起主动关闭,三次挥手完成后发送第四次挥手的ACK包后就进入这个状态,等待2MSL时间主要目的是:防止最后一个ACK包对方没有收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可以继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。
为什么是四次挥手,而不是三次或是五次、六次?
双方关闭连接要经过双方都同意。所以,首先是客服端给服务器发送FIN,要求关闭连接,服务器收到后会发送一个ACK进行确认。服务器然后再发送一个FIN,客户端发送ACK确认,并进入TIME_WAIT状态。等待2MSL后自动关闭。
conclusion:
1、为了保证客户端发送的最后一个ACK报文段能够到达服务器。即最后一个确认报文可能丢失,服务器会超时重传,然后服务器发送FIN请求关闭连接,客户端发送ACK确认。一个来回是两个报文生命周期。
如果没有等待时间,发送完确认报文段就立即释放连接的话,服务器就无法重传,因此也就收不到确认,就无法按步骤进入CLOSE状态,即必须收到确认才能close。
2、防止已经失效的连接请求报文出现在连接中。经过2MSL,在这个连续持续的时间内,产生的所有报文段就可以都从网络消失。
四、socket初使用(用代码去实现)
基于TCP协议的socket
sever端
import socket
# 1.创建一个代表服务器的socket对象
s = socket.socket() # 2.绑定IP地址和端口号(一般8000以后)
# 127.0.0.1 表示当前这个电脑的ip
address = ("127.0.0.1",8080)
s.bind(address) print("服务器已启动!") # 3.开始监听这个端口
# 5表示 可以有5个处于半连接状态的连接 指的不是最大连接数
s.listen(5)
print("test") # 4.接受连接请求
# 该函数是阻塞的 会卡主程序的执行,必须等到有一个客户端进来才会继续执行
# 返回元组 第一个是代表客户端的socket对象 第二客户端的地址信息
client,c_address = s.accept()
print("有一个连接已建立!")
print(c_address) # 5.读写数据
# 接受数据
res = client.recv(1024)
print(res) # 6.关闭连接
# s.close()
client端
import socket # 1.创建客户端的socket对象
c = socket.socket() # 2.指定服务器的ip和port
server_address = ("127.0.0.1",8080) # 3.建立连接
c.connect(server_address) # 4.读写数据
# 发送数据到服务器
c.send("hello 我是客户端!".encode("utf-8")) # 5.关闭连接
c.close()
基于UDP协议的socket
server端
import socket
# 1.创建socket对象
s = socket.socket(type=socket.SOCK_DGRAM) # 2.绑定端口和ip
s.bind(("127.0.0.1",10000)) while True:
# 3.接受数据
res = s.recv(1024)
print(res) while True:
msg = input(">>>:")
# 需要获取对方的ip和端口
#s.sendto(msg.encode("utf-8"), ("127.0.0.1", 10000)) # 关闭资源
s.close()
client端
import socket
# 1.创建socket对象
c = socket.socket(type=socket.SOCK_DGRAM)
while True:
msg = input(">>>:")
c.sendto(msg.encode("utf-8"),("127.0.0.1",10000)) c.close()
输出结果
client端:
>>>>>:hello
>>>>>:world
>>>>>:
sever端:
b'hello'
b'world'
练习:模拟一个qq多人聊天(由于udp无连接,所以可以同时多个客户端去跟服务端通信)
client1端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Wwl import socket udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) qq_name_dict = {
'Taylor': ('127.0.0.1', 8081),
'lana': ('127.0.0.1', 8081),
'Sia': ('127.0.0.1', 8081)
}
while True:
qq_name = input('请选择你要聊天的对象:').strip()
while True:
msg = input('请输入信息').strip()
if msg == 'q': break
udp_client.sendto(msg.encode('utf-8'), qq_name_dict[qq_name]) back_msg, addr = udp_client.recvfrom(1024)
print('收到来自%s %s 的消息%s' % (addr[0], addr[1], back_msg.decode('utf-8'))) udp_client.close()
client2端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Wwl import socket udp_client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) qq_name_dict = {
'Taylor': ('127.0.0.1', 8081),
'lana': ('127.0.0.1', 8081),
'Sia': ('127.0.0.1', 8081)
}
while True:
qq_name = input('请选择你要聊天的对象:').strip()
while True:
msg = input('请输入信息').strip()
if msg == 'q': break
udp_client.sendto(msg.encode('utf-8'), qq_name_dict[qq_name]) back_msg, addr = udp_client.recvfrom(1024)
print('收到来自%s %s 的消息%s' % (addr[0], addr[1], back_msg.decode('utf-8'))) udp_client.close()
同client1端
sever端:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author:Wwl import socket
udp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
udp_server.bind(('127.0.0.1',8081)) while True:
qq_msg,addr = udp_server.recvfrom(1024) print('来自[%s:%s]的一条消息:%s'%(addr[0],addr[1],qq_msg.decode('utf-8')))
back_qq_msg = input('请输入:').strip()
udp_server.sendto(back_qq_msg.encode('utf-8'),addr)
TCP/UDP协议、理解三次握手四次挥手、Socket的更多相关文章
- python摸爬滚打之----tcp协议的三次握手四次挥手
TCP协议的三次握手, 四次挥手 三次握手过程 1, 服务器时刻准备接受客户端进程的连接请求, 此时服务器就进入了LISTEN(监听)状态; 2, 客户端进程然后向服务器发出连接请求报文, 之后客户端 ...
- 网络架构,七层协议,三次握手四次挥手,socket套接字简单编程
一.单机架构 应用领域: 植物大战僵尸 office 二.CS架构 应用领域: QQ 大型网络游戏 计算机发展初期用户去取数据,直接就去主机拿,从这里开始就分出了客户端和服务端. 客户端:用户安装的软 ...
- OSI七层协议&TCP协议(三次握手四次挥手)
今日内容 python 基础回顾 软件开发架构 网络理论前戏 OSI 七层协议(五层) TCP协议 三次握手与四次挥手 UDP协议 内容详细 一.python 基础回顾 1.基本数据类型 整型 int ...
- TCP UDP协议的三次握手
接触网络协议栈TCP/IP的人,就一定绕不开的一个话题就是TCP的三次握手.下面我将简单介绍一下. 三次握手流程的本质,可以这么理解:TCP的三次握手其实是双方各一次握手,各一次确认,只是其中一次握手 ...
- tcp协议:三次握手四次挥手详解-转
https://www.cnblogs.com/welan/p/9925119.html
- web服务-1、http协议的三次握手四次挥手
知识点:http协议:它是基于tcp协议的,浏览器访问服务器,服务器把资源回给浏览器,这个过程都是遵循http协议的,否则无法完成,http早些年是1.0版本,现在基本上都是1.1版本了,俩个版本的区 ...
- Python进阶----网络通信基础 ,OSI七层协议() ,UDP和TCP的区别 , TCP/IP协议(三次握手,四次挥手)
Python进阶----网络通信基础 ,OSI七层协议() ,UDP和TCP的区别 , TCP/IP协议(三次握手,四次挥手) 一丶CS/BS 架构 C/S: 客户端/服务器 定义: ...
- TCP/IP协议 | TCP协议 | UDP协议 | 三次握手四次挥手
TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP.SMTP.TCP.UDP.IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP ...
- TCP协议—三次握手四次挥手的原理<转>
三次握手四次挥手的原理 TCP是面向连接的,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接.在TCP/IP协议中,TCP 协议提供可靠的连接服务,连接是通过三次握手进行初始化的.三 ...
随机推荐
- linux lsof用法
linux lsof命令详解 简介 lsof(list open files)是一个列出当前系统打开文件的工具.在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可 ...
- python 正则re.search
re.search 扫描整个字符串并返回第一个成功的匹配. 上码: import re line = "Cats are smarter than dogs"; searchObj ...
- python使用SAX解析xml
python 标准库包含SAX解析器,SAX用事件驱动模型,通过在解析XML的过程中触发一个个的事件并调用用户定义的回调函数来处理XML文件 在python中使用sax方式处理xml要先引入xml.s ...
- Linux:编译安装boost 1.69库
Boost库是为C++语言标准库提供扩展的一些C++程序库的总称,由Boost社区组织开发.维护.在C++的地位感觉可以和Spring在Java中相比. boost向来有准标准库之称,很多新特性例如智 ...
- Charles 从入门到精通 --转
文章目录 1. 目录及更新说明 2. Charles 限时优惠 3. 简介 4. 安装 Charles 5. 将 Charles 设置成系统代理 6. Charles 主界面介绍 7. 过滤网络请求 ...
- Java程序员秋招面经大合集(BAT美团网易小米华为中兴等)
Cvte提前批 阿里内推 便利蜂内推 小米内推 金山wps内推 多益网络 拼多多学霸批 搜狗校招 涂鸦移动 中国电信it研发中心 中兴 华为 苏宁内推 美团内推 百度 腾讯 招商银行信用卡 招银网络科 ...
- Java连接数据库 #04# Apache Commons DbUtils
索引 通过一个简单的调用看整体结构 Examples 修改JAVA连接数据库#03#中的代码 DbUtils并非是什么ORM框架,只是对原始的JDBC进行了一些封装,以便我们少写一些重复代码.就“用” ...
- Context initialization failed
Context initialization failed org.springframework.beans.factory.BeanDefinitionStoreException: Invali ...
- chrome platform
folder_extension: ---menifest.json ---navigator_change.js manifest.json { "manifest_version&quo ...
- PyTorch 中,nn 与 nn.functional 有什么区别?
作者:infiniteft链接:https://www.zhihu.com/question/66782101/answer/579393790来源:知乎著作权归作者所有.商业转载请联系作者获得授权, ...