TCP客户端
tcp的客户端要比服务器端简单很多,tcp和服务端建立连接后,直接发送数据
开发步骤
- 导入
socket
模块 - 创建
socket
套接字 - 建立tcp连接(和服务端建立连接)
- 开始发送数据(到服务端)
- 关闭套接字
参考代码
TCP客户端发送数据
# 1、导入socket模块
import socket
# 2、创建socket
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 3、建立tcp连接
tcp_client_socket.connect(("192.168.23.247", 7878))
# 4、开始发送数据
tcp_client_socket.send("哈哈哈,打不过我吧!?".encode())
# 5、关闭套接字
tcp_client_socket.close()
TCP客户端发送并接收数据
```python1、导入socket模块
import socket2、创建socket
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)3、建立tcp连接
tcp_client_socket.connect((“192.168.23.247”, 7878))4、开始发送数据
tcp_client_socket.send(“哈哈哈,打不过我吧!?”.encode())
开始接收对方回复的数据
recv_data = tcp_client_socket.recv(1024) print(“接收到数据:”, recv_data.decode())
5、关闭套接字
tcp_client_socket.close()
<a name="yA9sA"></a>
### 关键方法回顾
- `socket.socket(socket.AF_INET, socket.SOCK_STREAM)`
创建socket套接字对象,`socket.AF_INET`代表IPv4,`socket.SOCK_STREAM`TCP数据流
- `socket.connect(address)`
主动初始化TCP服务器连接,一般address的格式为元组(hostname, port),如果连接出错,返回socket.error错误。
- `socket.send(要发送的数据)`
向服务端发送数据,此处的数据必须是二进制类型(字符串则需要编码)
- `socket.recv(缓冲区大小)`
接收TCP数据,数据以二进制形式返回,bufsize指定要每次接收的最大数据量。
<a name="PbMoP"></a>
## TCP服务端
tcp服务器:和客户端建立连接后,接收/发送数据给客户端<br />![](https://cdn.nlark.com/yuque/0/2023/png/27903758/1685090894298-51d2d812-6fef-47b8-aa97-6f5a892e54e7.png#averageHue=%2381d353&clientId=u26139ad1-5aef-4&from=paste&id=ud8e924b3&originHeight=976&originWidth=1716&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u7c10c755-d1ae-406c-84d2-45c02844846&title=)
<a name="SvQdf"></a>
### 开发步骤
1. `socket`创建一个套接字
2. `bind`绑定ip和port
3. `listen`使套接字设置为被动模式
4. `accept`等待客户端的链接
5. `recv`/`send`接收发送数据
<a name="gGjGP"></a>
### 参考代码
<a name="e6Fan"></a>
#### 接收客户端消息并回复
```python
from socket import *
# 创建socket
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
# 服务IP和端口
address = ('', 7788)
# 绑定服务器IP和端口
tcp_server_socket.bind(address)
# 使用socket创建的套接字默认的属性是主动的,使用listen将其变为被动的,
# 参数128表示:允许同时排队等待连接的最大连接数为128
tcp_server_socket.listen(128)
# 如果有新的客户端来链接服务器,那么就产生一个新的套接字专门为这个客户端服务
# client_socket用来为这个客户端服务
# tcp_server_socket就可以省下来专门等待其他新客户端的链接
client_socket, ip_port = tcp_server_socket.accept()
print("已经连接客户端:", ip_port)
# 接收对方发送过来的数据
recv_data = client_socket.recv(1024) # 接收1024个字节
print('收到数据:%s' % recv_data.decode('gbk'))
# 发送一些数据到客户端
client_socket.send("好的,已经收到!~".encode('gbk'))
# 关闭为这个客户端服务的套接字,只要关闭了,就不能再为这个客户端服务了
# 如果还需要服务,只能再次重新连接
client_socket.close()
接受客户端发来的多条信息
...
while True:
# 接收对方发送过来的数据
recv_data = client_socket.recv(1024) # 接收1024个字节
if recv_data:
print('收到数据:%s' % recv_data.decode('gbk'))
# 发送一些数据到客户端
client_socket.send("好的,已经收到!~".encode('gbk'))
else:
break
...
允许客户端多次连接
# tcp 服务端:
import socket
# 1、创建套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2、绑定ip和端口
tcp_server_socket.bind(("192.168.174.87", 8081))
# 3、监听(让套接字由主动变为被动),只能接受客户端连接
tcp_server_socket.listen(128)
# 4、接收客户端连接
# 此处while True作用是可以接收客户端多次连接
while True:
# 每个客户端连接成功后,分配一个新的套接字
new_client_socket, ip_port = tcp_server_socket.accept()
print("【新客户端来了】:", ip_port)
# 5、开始数据传输, recv
# 此处的while True,表示可以多次接收客户端的消息
while True:
recv_content = new_client_socket.recv(1024)
# 如果客户端断开了连接,此时recv_content 接收到的数据为空
if recv_content:
# 保存客户端发来的信息
re_text = recv_content.decode("gbk")
print("收到客户端信息:", re_text)
# 回复客户端
new_client_socket.send("好的,收到.".encode())
else:
print("客户端可能断开连接!")
break
# 6、关闭和当前客户端的连接,当前客户端不能在进行通信了
new_client_socket.close()
# 7、关闭服务器(服务器不再接受新的客户端连接),服务器不再接收新的客户端连接(老的连接,继续服务)
tcp_server_socket.close()
注意,仔细想想不难发现,这里同时还是只能有一个客户端接入进来。
TCP应用程序开发总结
- TCP 客户端程序想要和 TCP 服务端程序进行通信时必须要先建立连接
- TCP 客户端程序一般不需要绑定端口号(会自动随机分配),因为客户端是主动发起建立连接的。
- TCP 服务端程序必须绑定端口号,否则客户端找不到这个 TCP 服务端程序。
- 执行
listen
后的socket套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。 - 当 TCP 客户端程序和 TCP 服务端程序连接成功后, TCP 服务端会会客户端产生一个新的套接字,收发客户端消息使用该套接字。
- TCP服务端关闭
accept
返回的新套接字意味着和这个客户端已经通信完毕。 - TCP服务端关闭自己的套接字意味着服务端关闭了,新的客户端不能连接服务端,但是之前已经接成功的客户端还能正常通信。
- 当客户端的套接字
close
后,服务器端的recv
会解除阻塞,返回的数据长度为0
;此时,服务端可以通过返回数据的长度来判断客户端是否已经下线, - 反之,如果服务端为客户端创建的的套接字对象
close
后,客户端的recv
也会解阻塞,返回的数据长度也为0
。