python创建TCP Client

1. TCP 客户端与服务端通信

python TCP server client
创建TCP 客户端与 TCP server通信

import socket
import time


host = '127.0.0.1'
port = 8081
addr = (host, port)
client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# 连接server
client.connect(addr)
# 向server发送数据
client.send(b'I am client')
# 接收server返回的数据
revcdata = client.recv(1024)
# 收到的数据都是bytes类型
print(revcdata.decode(encoding='utf-8'))
time.sleep(1)
client.close()

为了配合客户端测试,同时编写服务端代码

import socket

# 指定协议
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 让端口可以重复使用
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定ip和端口
server.bind(('0.0.0.0', 8081))
# 监听
server.listen(1)
# 等待连接
clientsocket, address = server.accept()
# 接收消息
data = clientsocket.recv(1024)
clientsocket.send('我已经收到'.encode(encoding='utf-8'))
clientsocket.close()
server.close()

先启动服务端,然后在另一个终端里启动客户端,客户端与服务端完成一次通信,随后都关闭

2. 客户端代码解读

客户端代码似乎和服务端代码很相似,对比一下有四处不同。

  1. 客户端代码没有bind
  2. 客户端代码没有listen
  3. 客户端代码没有accept
  4. 客户端需要connect

2.1 connect

服务端不需要去connect谁,它只需要等待客户端来连接它就可以了,所以客户端必须bind,指定监听的IP和端口,因此,在socket应用程序中,必须先启动服务端,启动后服务端进行listen,客户端发起connect,服务端accept

2.2 bind

客户端其实也能进行bind操作,指明用哪个端口与服务端通信,但通常来说不会这么做,原因很简单,服务端一般来说要一直提供服务,轻易不会停下来,而客户端却可能经常停下来,想想上一篇讲的time_wait,再有,如果客户端的程序是多线程的,多个线程里总不能同时去bind同一个端口吧。所以不bind是最好的,让操作系统来随机分配端口

2.3 send

send方法用于发送数据,数据类型必须是bytes类型,字符串与bytes类型之间的相互转换可以参考bytes 字节串
, send函数执行完了,不代表数据已经被发送出去了,函数返回,只是表示这些数据已经被放入到发送缓冲区了,至于何时被发送到网络上,由socket协议自己来决定。

send方法的返回值是本次发送数据的长度,假设你send的数据的长度是1000,send函数执行完了,其返回值可能小于1000,比如返回值是900,这就意味着只有前900个字节的数据被放入到发送缓冲区了,因此在send时,你必须检查send函数的返回值并和你要发送的数据长度做对比,遇到我刚才说的情况,你只好重新发送失败的那部分,可靠的写法类似这样

data = b'I am client'
sendlen = 0
while sendlen < len(data):
    successlen = client.send(data[sendlen:])
    sendlen += successlen

2.4 recv

关于recv,虽然参数是1024,但这不代表你就能接收到这么多的数据,这个参数的意思是我想接收1024个字节的数据,但socket协议最终给你的可能比你要求的少,想想也合理,因为TCP是不维护数据边界的,一次给你多少不影响你的分析,但绝不会超过你所要求的,如果缓冲区里有数据了,也没必要非得等到缓冲区的数据长度达到1024再给你。如果recv得到的数据长度是0,那就表示对方已经断开了连接

2.5 分包与粘包

一个tcp包最多可以装1460个字节的数据,所以如果你要发送的数据长度是2000个字节,那么这些数据最少要分成两份,也就是两个TCP包发过去,如果你频繁的发送长度只有10个字节的数据,那么为了不浪费网络带宽,这些大量的长度只有10的数据会被装进同一个TCP包中一起发送过去,这就是TCP的分包与粘包。这个对于接收方来说就是个麻烦,由于TCP自己不维护数据边界,因此应用程序本身必须对此进行处理,以便应对一段完整数据被分多个包发送(分包)和多个小段数据被一起发送(粘包)的情况,下一篇将给出一个非常简单的解决方案

扫描关注, 与我技术互动

QQ交流群: 211426309

加入知识星球, 每天收获更多精彩内容

分享日常研究的python技术和遇到的问题及解决方案