1.特点:
(1)提供可靠的数据传输
- 可靠性:指数据传输中无失序、无差错、无丢失、无重复
(2)所有消息传输前,一定会建立连接,传输后一定会断开连接
(3)三次握手
:在进行面向连接的数据传输前进行传输连接的过程
- 1、
客户端向服务器发起连接请求
- 2、
服务器接收到连接请求确认,返回报文
- 3、
客户端收到回复,进行连接建立
(4)四次挥手:在进行面向连接的数据传输时,断开连接的过程
- 1、
主动方发送报文,告知被动方要断开连接
- 2、
被动方返回报文,告知收到请求,准备断开
- 3、
被动方再次发送报文给主动方,告知准备完毕可以断开
- 4、
主动方发送报文进行断开
2.应用情况:
- 适用于传输较大的内容或文件,网络情况良好,需要保证 传输可靠性的情况
- 比如:
聊天信息,文件上传下载,邮件传输,网页获取
3.流式套接字
(1)说明
- 流式套接字(
sock_stream
):传输层基于tcp
的协议进行通信
(2)使用流程
- 1、创建套接字
sockfd=socket(socket_family=AF_INET, socket_type=SCOK_STREAM)
参数说明:
socket_family:(选择地址族类型)AF_INET(使用ipv4)
socket_type:(套接字类型)SOCKET_STREAM(流氏套接字)
返回值:
返回一个套接字对象
- 2、绑定地址(ip端口号)
sockfd.bind(("", 8080))
参数:
一个二元元组(ip, port)
- 3、将套接字设置可监听
sockfd.listen(1024)
参数:
n是一个正整数,表示监听等待队列的大小
- 4、等待接收连接请求
connfd,addr=sockfd.accept()
功能:
阻塞等待处理客户端连接
返回值:
1、一个新的套接字用户来和客户端通信(connfd)
2、连接的客户端地址(addr)
- 5、收发消息
data=connfd.recv(1024)
- 6、关闭套接字
sockfd.close()
4.套接字对象
1、s.fileno()
功能:获取套接字的文件描述符
文件描述符:每一个IO事件操作系统都会分配一个不同的正整数与之匹配,该正整数即为此IO操作的文件描述- 2、
s.type
功能:获取套接字的类型 - 3、
s.family
功能:获取地址族 - 4、
s.getsockname()
功能:获取套接字绑定地址 - 5、
s.getpeername()
功能:获取到实例连接的客户端地址(addr) - 6、
s.setsockopt(level,optname,value)
功能:设置套接字选项,丰富修改原有套接字功能(端口可重用)
参数:
level:设置选项的类型(SOL_SOCKET常规选项)
optname:选项类型中的子选项(SO_REUSEADDR)
value:为选定选项设定值
5.TCP套接字最简单程序示例
- 服务端
from socket import *
import sys
if len(sys.argv) <= 2:
print("请输入正确参数(IP地址和端口)")
sys.exit()
addr = sys.argv[1]
port = int(sys.argv[2])
# 1、创建套接字
sockfd = socket(AF_INET, SCOK_STREAM)
# 2、绑定地址(ip端口号)
sockfd.bind((addr, port))
# 3、将套接字设置可监听
sockfd.listen(1024)
# 4、等待连接
connfd,addr = sockfd.accept()
print("连接来自:",addr)
# 5、接收消息
data = connfd.recv(1024)
print("收到信息:",data)
# 6、发送消息
connfd.send("你好!")
# 7、关闭套接字
sockfd.close()
- 客户端
from socket import *
import sys
if len(sys.argv) <= 2:
print("请输入正确参数(IP地址和端口)")
sys.exit()
addr = sys.argv[1]
port = int(sys.argv[2])
# 1、创建套接字
sockfd = socket()
# 2、请求连接
sockfd.connect((addr, port))
# 3、发送消息
sockfd.send("很高兴认识你")
# 4、发送消息
data = recv(1024)
print("收到信息,内容为:", data)
# 5、关闭套接字
close()
# 首先启动服务端,服务端等待连接
ubantu@ubantu-virtual-machine:~/mysocket$ python3 tcp_server.py 127.0.0.1 8080
# 再启动客户端
ubantu@ubantu-virtual-machine:~/mysocket$ python3 tcp_client.py 127.0.0.1 8080
收到信息,内容为: 你好!
ubantu@ubantu-virtual-machine:~/mysocket$
# 此时服务端收到来自客户端的连接信息
连接来自: ('127.0.0.1', 39512)
收到信息: 很高兴认识你
ubantu@ubantu-virtual-machine:~/mysocket$
上述事例中我们仅能收发一条数据,接下来我们对其进行完善,使其能够一直进行消息的收发。
- 服务端
from socket import *
import sys
if len(sys.argv) <= 2:
sys.exit("请输入参数(IP地址和端口号)")
addr = sys.argv[1]
port = int(sys.argv[2])
# 1.创建套接字
sockfd = socket()
# 设置端口可重用
sockfd.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
# 2.绑定地址
sockfd.bind((addr, port))
# 3.设置监听
sockfd.listen(10)
print("listen to 9000...")
# 4.循环等待连接
while True:
connfd, addr = sockfd.accept()
print("receive from ", addr)
# 5.循环收发消息
while True:
# 接收消息
data = connfd.recv(1024)
if not data:
break
print("收到消息:", data.decode())
# 发送消息
data = input("回复>>")
connfd.send(data.encode())
# 6.关闭套接字
connfd.close()
sockfd.close()
- 客户端
from socket import *
import sys
if len(sys.argv) <= 2:
sys.exit("请输入参数(IP地址和端口号)")
addr = sys.argv[1]
port = int(sys.argv[2])
# 1.创建套接字
sockfd = socket()
# 2.绑定地址
sockfd.connect((addr, port))
# 3.消息收发
while True:
# 发送消息
data = input("发送>>")
if not data:
break
sockfd.send(data.encode())
# 接收消息
data = sockfd.recv(1024)
print("收到回复:",data.decode())
# 6.关闭套接字
sockfd.close()
上述事例中我们实现了数据的无线次收发,但我们发现每个人一次只能发送一条数据,只有等到对方回复之后才能再次发送,为了实现发送接收自由,我们就需要使用多任务进行编程
(多任务编程将会在接下来的文章中写到),使其能够自由的进行数据收发。
6. 文件传输示例
(1)服务端
from socket import *
s = socket(AF_INET,SOCK_STREAM)
s.bind(('176.234.90.40',9000))
s.listen(5)
connfd, addr = s.accept()
print("connect from:",addr)
f = open("file.txt",'rb')
while True:
data = f.read(1024)
if not data:
break
connfd.send(data)
f.close()
connfd.close()
s.close()
(2)客户端
from socket import *
s=socket()
s.connect(('176.234.90.40',9000))
f=open("file_bak.txt",'wb')
while True:
data = s.recv(1024)
if not data:
break
f.write(data)
f.close()
s.close()
启动服务端
启动客户端
我们查看结果,是否传输成功