如何用 Python 实现 TCP 的连接与通信?

网络连接与通信是我们学习任何编程语言都绕不过的知识点 。Python 也不例外,下面就介绍因特网的核心协议 TCP,以及如何用 Python 实现 TCP 的连接与通信 。
TCP 协议TCP协议(Transmission Control Protocol,传输控制协议)是一种面向连接的传输层通信协议,它能提供高可靠性通信,像 HTTP/HTTPS 等网络服务都采用 TCP 协议通讯 。那么网络通讯方面都会涉及到 socket 编程,当然也包括 TCP 协议 。
Network Socket我们来看看定义:

Network Socket(网络套接字)是计算机网络中进程间通信的数据流端点,广义上也代表操作系统提供的一种进程间通信机制 。
这些计算机术语都很学术,难于理解,每个字都认识,加在一起就不认识了 。我们可以通俗地理解成发快递:A 需要给 B 寄快递,首先需要知道 B 的地址和手机号码,那么这个地址就相当于 网络中的主机 IP 地址,而手机就相当于 主机的端口号 。然后 A 还需要指定哪家快递公司,是顺丰还是中通?这个快递公司就相当于通信的传输协议 。
TCP 连接流程上述快递的例子中,寄快递的我们可以叫做客户端,收快递的我们叫做服务器 。专业点就是主动发起连接的一方叫做客户端,被动响应的一方叫做服务器 。例如,我们在浏览器中访问百度搜索时,我们自己的电脑就是客户端,浏览器会向百度的服务器发送连接请求,如果百度的服务器接受了我们的请求,那么一个 TCP 连接就建立起来了,后面就是百度向我们传输搜索结果了 。
【如何用 Python 实现 TCP 的连接与通信?】我们来看一个流程图:
如何用 Python 实现 TCP 的连接与通信?

文章插图
 
TCP服务器的建立可以归纳这几步:
  • 创建 socket(套接字)
  • 绑定 socket 的 IP 地址和端口号
  • 监听客户端的连接请求
  • 接受客户端的连接请求
  • 与客户端对话
  • 关闭连接
TCP客户端的创建可总结为这几步:
  • 创建 socket(套接字)
  • 连接服务器 socket
  • 与服务器对话
  • 关闭连接
这里需要注意的是 TCP 客户端连接到服务器的 IP 和端口号必须是 TCP 服务器的 IP 和监听的端口号,服务器调用 listen() 开始监听端口,然后调用 accept() 时刻准备接受客户端的连接请求,此时服务器处于阻塞状态,直到服务器监听到客户端的请求后,接收请求并建立连接为止 。
TCP 客户端创建 socket 连接,可以这样做:
 
# 导入socket库import socket# 创建一个sockets = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 建立连接s.connect(("127.0.0.1", 6000)) 
创建 socket 时,第一个参数 socket.AF_INET 表示指定使用 IPv4 协议,如果要使用 IPv6 协议,就指定为 socket.AF_INET6 。SOCK_STREAM 指定使用面向流的 TCP 协议 。然后我们调用 connect() 方法,传入 IP 地址(或者域名),指定端口号就可以建立连接了 。
接下来我们就可以向服务器发送数据了:
s.send(b'Hello, Mr Right!')
 
接收数据时,调用 recv(max) 方法,一次最多接收指定的字节数,因此,在一个 while 循环中反复接收,直到 recv() 返回空数据,表示接收完毕,退出循环 。
 
#接收数据 buffer=[] whileTrue: #每次最多接收1k字节 d=s.recv(1024) ifd: buffer.Append(d) else:break data=https://www.isolves.com/it/cxkf/yy/Python/2019-12-26/b''.join(buffer)
最后,我们需要关闭连接,很简单:
 
  •  
s.close()
 
TCP 服务器相比于客户端,服务器端稍微复杂一些,需要先绑定一个 IP 地址和端口号,然后监听客户端的请求,收到请求后丢到一个线程去处理 。
创建 socket 跟客户端方法一样:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
接下来需要绑定监听地址和端口:
 
s.bind(('127.0.0.1', 6000))
 
然后就可以开始监听端口了,监听时需要传入一个参数,指定等待连接的最大数量:
 
s.listen(5)
 
接下来就是无限循环等待客户端的连接,直到有连接请求过来,就用一个线程去处理:
whileTrue: #接受一个新连接 sock,addr=s.accept() #创建新线程来处理TCP连接 t=threading.Thread(target=tcplink,args=(sock,addr)) t.start() 
这里为什么需要多线程处理呢?想象一下菜鸟驿站,如果里面只有一个人的话,那么多个人寄件就需要排队,一个个来;但是如果有多个人的话,那么每个人都可以处理一个寄件请求 。


推荐阅读