TCP 3ウェイハンドシェイクと4波
背景説明
OSIネットワークモデルは、IP層を説明することで、私たちが知っているネットワーク層は、2つのホスト間の通信を実現することができます。実際のエンティティがホストのプロセスであるため、実際にはない場合、ホストは、データを交換するプロセスと別のホストプロセスです。
IPの唯一の宛先ホストにデータを送信するためのプロトコルが、ホストアプリケーションに固有のものではありません。そして、アプリケーション間の通信は、通信をエンドツーエンドです。
TCP:転送が完了した後、接続指向のサービス、データを送信する前に、あなたが最初の接続を確立する必要があり、接続が解放されます。したがって、TCPは信頼性の高いデータ転送サービスであるが、これは必然的に支出を増加します。アプリケーション層のプロトコルに対応して、SMTP、TELNET、HTTP、FTP等です。
一般的に知られているポート番号
アプリケーション | よく知られているポート | トランスポート層 |
---|---|---|
FTP | 21,20 | TCP |
TFTP | 69 | UDP |
TELNET | 23 | TCP |
SMTP | 25 | TCP |
DNS | 53 | UDP |
HTTP | 80 | TCP |
SSH | 22 | TCP |
TCPの概要
基本的なオブジェクトとしてTCP接続は、各TCP接続があれば、我々は、例えば、すなわちソケット構成スプライスさIPアドレス、ポート番号として定義されているエンドソケット(ソケット)、呼び出し両端点を有しています、IPは192.3.4.26、ポート番号は80です
だから、ソケットがあります192.3.4.26:80
TCPコネクションの確立(スリーウェイハンドシェイク)
- 最开始的时候,客户端和服务端都是处于CLOSED关闭状态。主动打开连接的为客户端,被动打开的连接是服务器。如果要进入来连接,会经过如下步骤:
- TCP服务器进程先创建传输控制块TCP,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
- 客户端先创建传输控制块TCP,然后向服务器发连接请求报文,报文里包括SYN报头;
- 服务端接收到客户端传入的报文,如果同意连接,就会发出确认报文,此时报文中包括SYN和ACK报头;
- 客户端接收到服务端传来的报文,如果确认连接,就会返回给ACK报头的报文给服务端,此时客户端进入连接状态;
- 服务端接收到客户端传入的确认连接报文后,也进去连接状态,这样双发就建立了连接,可以进行通信了。
TCP四次挥手
- 数据传输完毕后,双方就可以释放连接。最开始的时候,客户端和服务端都处于ESTABLISHED(连接)状态,然后客户端主动关闭,服务端被动关闭。
- 客户端进程发出连接释放报文,并且停止发送数据。报文包括FIN报头;
- 服务端接收到包括FIN报头的释放报文,发出确认报文,ACK报头,但是此时服务端可能还会传输数据给客户端;
- 客户端接受到服务器返回的包含ACK报头的报文后,等待把最后的数据传输完毕;
- 数据传输完毕后,服务端就会像客户端发送报文,包含FIN,ACK报头,等待客户端确认;
- 客户端接收到服务端发送的释放连接报文请求后,如果要释放连接,就会返回给服务端一个ACK报头的报文,客户端进入等待状态。此时客户端的连接还没有释放,必须经过2MSL的时间后,才会释放连接;
- 服务端接收到客户端发送的包含ACK报头的报文,直接释放连接,进入CLOSDED(关闭)状态。
如果已建立连接,客户端突然断开,会怎么办呢?
TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
基于TCP协议的套接字编程
什么是Socket
socket是应用层与TCP/IP协议通信的中间软件抽象层,他是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议隐藏在Socket接口后面。
套接字发展史及分类
套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。
套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。
基于文件类型的套接字家族
套接字家族名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用就是底层的文件系统来取数据,两个套接字进程运行在同一个机器上,可以通过访问一个文件系统间接完成通信
基于网络类型的套接字家族
套接字家族名字:AF_INET
套接字工作流程
服务端:初始化Socket---->然后端口绑定(bind)---->对端口进行监听(listen)---->调用accept接受
客户端:初始化Socket---->连接服务器(connect)
如果客户端和服务端连接成功,则可以进行连接。客户端发送信息,服务端处理请求,然后再把数据传给客户端。
import socket
# socket_family:可以为AF_UNIX或AF_INET
# socket_type:可以是SOCK_STREAM或SOCK_DGRAM
# protocol:一般不填,默认为0
socket.socket(socket_family, socket_type, protocal=0)
# 获取tcp/ip套接字
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 获取udp/ip套接字
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
服务端套接字函数
方法 | 用途 |
---|---|
bind() | 绑定(主机,端口号)到套接字 |
listen() | 开始TCP监听 |
accept() | 被动接受TCP客户的连接,(阻塞式)等待连接的到来 |
客户端套接字函数
方法 | 用途 |
---|---|
connect() | 主动初始化TCP服务器连接 |
connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共用途的套接字函数
方法 | 用途 |
---|---|
recv() | 接收TCP数据 |
send() | 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完) |
sendall() | 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完) |
recvfrom() | 接收UDP数据 |
sendto() | 发送UDP数据 |
getpeername() | 连接到当前套接字的远端的地址 |
getsockname() | 当前套接字的地址 |
getsockopt() | 返回指定套接字的参数 |
setsockopt() | 设置指定套接字的参数 |
close() | 关闭套接字 |
面向锁的套接字函数
方法 | 用途 |
---|---|
setblocking() | 设置套接字的阻塞与非阻塞模式 |
settimeout() | 设置阻塞套接字操作的超时时间 |
gettimeout() | 得到阻塞套接字操作的超时时间 |
面向文件的套接字函数
方法 | 用途 |
---|---|
fileno() | 套接字的文件描述符 |
makefile() | 创建一个与该套接字相关的文件 |
基于TCP协议的套接字编程
服务端
# 服务端.py
import socket
# 1、初始化服务端
server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 2、绑定端口
server.bind(('127.0.0.1', 8000))
# 3、建立监听
server.listen(5)
# 4、等待客户端连接
print('start...')
conn, client_addr = server.accept()
# 5、通信
data = conn.recv(1024) # 接受信息的最大字节数,默认为1024个字节
print(data.decode('utf-8')) # 数据传输的是二进制
conn.send(data.upper())
# 6、断开连接
conn.close()
# 7、关闭服务器
server.close()
客户端
# 客户端.py
from socket import *
# 1、初始化客户端
client = socket(AF_INET, SOCK_STREAM)
# 2、连接服务器
client.connect(('127.0.0.1', 8000))
# 3、通信
msg = input('请输入你想传输的信息>>>')
client.send(msg.encode('utf-8')) # 以二进制形式发送数据
data = client.recv(1024)
print(data)
# 4、关闭连接
client.close()