Python TCP 编程

1. TCP 介绍

2. TCP Socket 代码示例

 

 

1. TCP 介绍

详见《TCP:与 UDP 区别、三次握手、四次挥手、Socket 编程》

TCP 与 UDP 在通信模型上的区别

UDP 通信模型

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

TCP 通信模型

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

 

2. TCP Socket 代码示例

TCP 服务器

在生活中,如果想让别人能更够打通咱们的电话获取相应服务的话,需要做以下几件事情:

  1. 买个手机
  2. 插上手机卡
  3. 设计手机为正常接听状态(即能够响铃)
  4. 静静的等着别人拨打

如同上面的电话机过程一样,在程序中,如果想要完成一个 TCP 服务器的功能,需要的流程如下:

  1. socket 创建一个套接字
  2. bind 绑定 ip 和 port
  3. listen 使套接字变为可以被动连接
  4. accept 等待客户端的链接
  5. recv/send 接收发送数据

示例:

 1 import socket
 2 
 3 # 创建socket
 4 tcpSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 5 
 6 # 绑定本地信息
 7 address = ("", 7788)
 8 tcpSocket.bind(address)
 9 
10 # 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的连接
11 tcpSocket.listen(5)
12 
13 while 1:
14     # 当有新的客户端来连接服务器时,就会产生一个新的套接字来专门为这个客户端服务
15     print("等待客户端连接...")
16     # newSocket就是用来为这个新来的客户端服务的
17     # tcpSocket就可以省下来专门等待其他新客户端的连接
18     newSocket, clientAddr = tcpSocket.accept()
19     # 打印客户端的IP与端口
20     print("Connected by: ", clientAddr)
21 
22     # 开始数据传输
23     try:
24         limit_time = 10
25         # 设置若10秒内没有收到数据则抛出异常
26         newSocket.settimeout(limit_time) 
27         # 接收对方发送过来的数据,最大接收1024个字节
28         recvData = newSocket.recv(1024)
29         print("接收到数据为:", recvData.decode())
30         # 发送一些数据给客户端
31         # 1)send:返回值是发送的字节数量, 这个数量值可能小于要发送的字节数。如果有错误,则会抛出异常。
32         # 2)sendall:尝试发送所有数据, 成功则返回None, 失败则抛出异常。
33         newSocket.send("Thank you!".encode())
34         # 关闭为这个客户端服务的套接字。只要关闭了,就意味着为不能再为这个客户端服务了,如果还需要服务,只能再次重新连接
35         newSocket.close()
36     except socket.timeout:
37         print('%s秒未接收到客户端数据,断开连接' % limit_time)
38         newSocket.close()  # 关闭连接
39         break
40     except Exception:
41         print("与客户端连接发生异常,断开连接")
42         newSocket.close()  # 关闭连接
43         break
44 
45 # 关闭监听套接字。只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
46 tcpSocket.close()

socket.listen([backlog])

该方法用于限制建立 socket 连接申请的个数。如果 backlog 指定了(最少是 0,如果比 0 小,系统默认改成 0),则将连接申请的数量限制为 backlog 个,如果没有指定,将指派一个默认的合理值。

事实上 accept 方法一次只能接收一个 client 的连接申请,而 client 则是多个的,这样 socket 会设计一个队列来存储 client 的连接申请则是理所当然的,于是 accept 便从这个队列里提取首位成员处理即可。而 backlog 参数的含义便是这个队列的最大值,也就是同时受理连接申请的最大值。如果队列满了便需要 client 重新 connect。

  • Windows、Mac 此连接参数有效;
  • Linux 此连接参数无效,默认最大。这就是很多 HTTP 服务器需用 linux 系统的原因。

运行效果

TCP 客户端

TCP 客户端要比服务器端简单很多。如果说服务器端是需要自己买手机、查手机卡、设置铃声、等待别人打电话流程的话,那么客户端就只需要找一个电话亭,拿起电话拨打即可,流程要少很多。

示例:

 1 import socket
 2 
 3 # 创建socket
 4 tcpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 5 
 6 # 连接服务器端
 7 serAddress = ("192.168.3.4", 7788)
 8 tcpClientSocket.connect(serAddress)
 9 
10 # 提示用户输入数据
11 sendData = input("请输入要发送给服务器的数据:")
12 
13 tcpClientSocket.send(sendData.encode())
14 
15 # 接收对方发送过来的数据,最大接收1024个字节
16 recvData = tcpClientSocket.recv(1024)
17 print("接收到数据为:", recvData.decode())
18 
19 # 关闭监听套接字。只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
20 tcpClientSocket.close()

运行效果

 

应用:1V1 聊天

服务器端

 1 import socket
 2 
 3 # 创建socket
 4 tcpServerSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 5 
 6 # 绑定本地信息
 7 address = ("", 7788)
 8 tcpServerSocket.bind(address)
 9 
10 # 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,这样就可以接收别人的连接了
11 tcpServerSocket.listen(5)
12 
13 while True:
14 
15     # 如果有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务器
16     # newSocket用来为这个客户端服务
17     # tcpSerSocket就可以省下来专门等待其他新客户端的连接
18     newSocket, clientAddr = tcpServerSocket.accept()
19     
20     while True:
21     
22         # 接收对方发送过来的数据,最大接收大小为2014字节
23         recvData = newSocket.recv(1024).decode()
24         
25         # 如果对方发送“88”,则意味着客户端关闭连接
26         if recvData == "88":
27             print("Receive:", recvData)
28             print("----关闭聊天----")
29             break
30         else:
31             print("Receive:", recvData)
32             sendData = input("Send:")
33             newSocket.send(sendData.encode())
34             
35     # 关闭这个客户端服务的套接字,只要关闭了,就意味着为不能再为这个客户端服务了
36     # 如果还需要服务,只能再次重新连接
37     newSocket.close()
38 
39 # 关闭监听套接字,只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
40 tcpSerSocket.close()    

客户端

 1 import socket
 2 
 3 # 创建socket
 4 tcpClientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 5 
 6 # 连接服务器端
 7 serAddress = ("localhost", 7788)
 8 tcpClientSocket.connect(serAddress)
 9 
10 while True:
11 
12     # 提示用户输入数据
13     sendData = input("Send:")
14     
15     tcpClientSocket.send(sendData.encode())
16     if sendData == "88":
17         break
18     else:
19         # 接收对方发送过来的数据,最大接收1024个字节
20         recvData = tcpClientSocket.recv(1024)
21         print("Receive:", recvData.decode())
22 
23 # 关闭监听套接字。只要这个套接字关闭了,就意味着整个程序不能再接收任何新的客户端的连接
24 tcpClientSocket.close()

运行效果

 

posted @ 2020-03-20 22:51  Juno3550  阅读(194)  评论(0编辑  收藏  举报