socket-tcp

1.TCP介绍

    TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为 TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

    TCP通信需要经过创建连接、数据传送、终止连接三个步骤。

    TCP通信模型中,在通信开始之前,一定要先建立相关的连接,才能发送数据,类似于生活中,"打电话""。

2.TCP特点

2.1 面向连接

    通信双方必须先建立连接才能进行数据的传输,双方都必须为该连接分配必要的系统内核资源,以管理连接的状态和连接上的传输。

    双方间的数据传输都可以通过这个连接进行。

    完成数据交换后,双方断开此连接,以释放系统资源。

    这种连接是一对一的。

    因此TCP不适用于广播的应用程序,基于广播的应用程序请使用UDP协议

2.2 可靠传输

1)TCP采用发送应答机制

    TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功

2)超时重传

    发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。

    TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的包发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据包就被假设为已丢失将会被进行重传。

3)错误校验

    TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。

4) 流量控制和阻塞管理

    流量控制用来避免主机发送得过快而使接收方来不及完全收下。

3. TCP与UDP的不同点

    1.面向连接

    2.有序数据传输

    3.重发丢失的数据包

    4.舍弃重复的数据包

    5.无差错的数据传输

    6.阻塞/流量控制

4 .udp通信模型

    udp通信模型中,在通信开始之前,不需要建立相关的连接,只需要发送数据即可,类似于生活中,"写信"。

5.TCP通信模型

    tcp通信模型中,在通信开始之前,一定要先建立相关的连接,才能发送数据,类似于生活中,"打电话"。

6.tcp的客户端与服务端

    tcp有严格的客户端和服务端之分。基于 TCP 传输方式的通信就必须事先建立连接, 则有一方是主动连接的,而另一方是被连接的; 主动连接的一方一般都是客户端, 被连接的一方一般都是服务端。

6.1.客户端构建流程:

示例代码:

import    socket

# 创建socket

tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 目的信息

server_ip = input("请输入服务器ip:")

server_port = int(input("请输入服务器port:"))

# 连接服务器

tcp_client_socket.connect((server_ip, server_port))

# 提示用户输入数据

send_data = input("请输入要发送的数据:")

tcp_client_socket.send(send_data.encode("utf-8"))

# 接收对方发送过来的数据,最大接收1024个字节

recvData = tcp_client_socket.recv(1024)

print('接收到的数据为:', recvData.decode('gbk'))

# 关闭套接字

tcp_client_socket.close()

6.2.服务端构建流程:

1. socket创建一个套接字

2. bind绑定ip和port

3. listen使套接字变为可以被动连接,即开启监听

4. accept等待客户端的连接

5. recv/send接收发送数据

示例代码:

import    socket

# 创建socket

tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 本地信息

address = ('',7788)

# 绑定IP和端口号

tcp_server_socket.bind(address)

# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的连接请求

tcp_server_socket.listen(5)# 参数:backlog=5 表示积压的客户端连接请求最多5个, 超过5个,则拒绝连接

# 如果有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务

# client_socket用来为这个客户端服务

# tcp_server_socket就可以省下来专门等待其他新客户端的连接

client_socket, clientAddr = tcp_server_socket.accept()

# 接收对方发送过来的数据

recv_data = client_socket.recv(1024)# 最多接收1024个字节

print('接收到的数据为:', recv_data.decode('gbk'))

# 发送一些数据到客户端

client_socket.send("thank you !".encode('gbk'))

# 关闭为这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接

client_socket.close()

7.tcp注意点

1. tcp服务端一般情况下都需要绑定,否则客户端找不到这个服务端

2. tcp客户端一般不绑定,因为是主动连接服务端,所以只要确定好服务端的ip、port等信息就好,本地客户端可以随机

3. tcp服务端中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务端时必须要做的

4. 当客户端需要连接服务端时,就需要使用connect进行连接,udp是不需要连接的而是直接发送,但是tcp必须先连接,只有连接成功才能通信

5. 当一个tcp客户端连接服务端时,服务端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务

6. listen后的套接字是被动套接字,用来接收新的客户端的连接请求的,而accept返回的新套接字是标记这个新客户端的

7. 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够连接服务端,但是之前已经连接成功的客户端正常通信。

8. 关闭accept返回的套接字意味着这个客户端已经服务完毕

9. 当客户端的套接字调用close后,服务端会recv解堵塞,并且返回的长度为0,因此服务端可以通过返回数据的长度来区别客户端是否已经下线

8.tcp的三次握手与四次挥手


    1. TCP的6个标志位

    SYN:发起一个新连接

    FIN:释放一个连接

    ACK:确认

    RST:重置连接

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

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

    2. tcp的三次握手

    第一次握手:主机A发送位码为syn=1,随机产生seq number=1234567的数据包到服务器,主机B由SYN=1知道,A要求建立联机;

    第二次握手:主机B收到请求后要确认联机信息,向A发送ack number=(主机A的seq+1),syn=1,ack=1,随机产生seq=7654321的包;

    第三次握手:主机A收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。

    3. tcp的四次挥手

    由于TCP连接是双向的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭,上图描述的即是如此。

    第一次挥手: Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

    第二次挥手: Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1,Server进入CLOSE_WAIT状态。

    第三次挥手: Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

    第四次挥手: Client收到FIN后,Client进入TIME_WAIT(TIME_WAIT等待2MSL时间,范围在1-4分钟)状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

猜你喜欢

转载自blog.csdn.net/chenzheng_blog/article/details/80464159