TCP/IP概述
◆ 关于传输层的TCP和UDP协议
TCP是通过三次握手建立的传输控制协议,而UDP是一种无连接的用户数据报协议,实时性较好。
• 当对数据可靠性要求较高或者网络状况不是很好时,采用TCP协议;
• 如果对实时性要求较高或者网络状况很好(如局域网)的情况下可以选择使用UDP协议。
Socket
常用的socket类型有2种
(1)流式socket(SOCK_STREAM)
提供可靠的,面向连接的通信流,采用TCP协议
(2)数据报socket( SOCK_DGRAM)
定义了一种无连接服务,采用UDP协议
▁▂▃▄▅▆▇█
socket编程的基本函数有socket()、bind()、listen()、accept()、send()、sendto()、recv()、recvfrom()等
■ socket():该函数用于建立一个socket连接
■bind():该函数用于将本地IP地址绑定到端口号
■listen():创建一个等待队列,在其中存放未处理的客户端连接请求
■accept():接收客户端连接请求
■connect():与服务器建立连接
■send()和recv():发送和接收数据
■sendto()和recvfrom():与send()和recv()类似,当用UDP时,可以在之前没有使用connect()的情况下,自动寻找指定地址并进行连接
下面是一个简单的TCP通信演练
服务器端:
import socket
# 创建实例
sk=socket.socket()
# 定义绑定ip和端口号
ip_port=("127.0.0.1",8888)
# 绑定监听
sk.bind(ip_port)
# 最大连接数
sk.listen(5)
while True:
print("正在等待接收数据")
# 接收连接请求
conn,address=sk.accept()
# 发送消息给客户端
msg="连接成功"
conn.send(msg.encode())
while True:
# 不断接收客户端信息
data=conn.recv(1024)
print("收到客户端信息:"+data.decode())
# 接收到退出指令
if data==b'exit':
break
# 处理客户端信息
str_back="已经收到你的信息:"
conn.send(str_back.encode())
conn.send(data)
# 主动关闭连接
conn.close()
非阻塞服务器端:
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def setup(self):
pass
def handle(self):
# 连接变量
conn=self.request
# 消息发送
msg="hello"
conn.send(msg.encode())
while True:
data=conn.recv(1024)
print(data.decode())
if data == b"exit":
break
# 给客户端发送回执
str_back = "已经收到你的信息:"
conn.send(str_back.encode())
conn.send(data)
conn.close()
def finish(self):
pass
if __name__ =="__main__":
# 创建多线程实例
server=socketserver.ThreadingTCPServer(("127.0.0.1",8888),MyServer)
# 开启异步多线程,等待连接
server.serve_forever()
ps:如果遇到xxx is not allowed to run in parallel的问题
可以在Run > Edit Configurations下,勾选对应文件的 Allow parallel run
客户端:
import socket
# 创建实例
client=socket.socket()
# 定义绑定ip和端口号
ip_port=("127.0.0.1",8888)
# 连接服务器
client.connect(ip_port)
while True:
# 接收服务器信息
data = client.recv(1024)
print(data.decode())
# 发送消息给服务器
msg_input=input("请输入要发送的消息:")
client.send(msg_input.encode())
if msg_input =="exit":
break
服务器端
import socket
sk=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
ip_port=("127.0.0.1",8888)
sk.bind(ip_port)
while True:
data=sk.recv(1024)
print(data.decode())
客户端:
import socket
client=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
ip_port=("127.0.0.1",8888)
while True:
msg_input = input("请输入要发送的消息:")
if msg_input =="exit":
break
client.sendto(msg_input.encode(),ip_port)
client.close()
文件发送与接收
客户端发送文件:
import socket
# 创建实例
client=socket.socket()
# 定义绑定ip和端口号
ip_port=("127.0.0.1",9999)
# 连接服务器
client.connect(ip_port)
# 文件分割上传
with open('sock_server_tcp2.py','rb') as f:
for i in f:
client.send(i)
# 等待接受完成标志
data=client.recv(1024)
if data !=b'succeed':
break
# 给服务器端发送结束信号
client.send('quit'.encode())
服务器端接收文件:
import socket
sk=socket.socket()
ip_port=("127.0.0.1",9999)
sk.bind(ip_port)
sk.listen(5)
while True:
conn,address=sk.accept()
while True:
# 接收文件为二进制可添加模式
with open("file","ab") as f:
data=conn.recv(1024)
if data==b'quit':
print("接收完成")
break
f.write(data)
# 每次接受完成之后,给发送端发送一个接收完成标志
conn.send('succeed'.encode())
sk.close()