目录
Socket概念
Python Socket编程
发送接收缓冲 消息格式定义
Socket概念Socket套接字,一种独立于协议的网络编程接口,就是对网络中不同主机上的应用进程之间进行双向通信的端点。
TCP把连接作为最基本的对象,每一条TCP连接都有两个端点,这种端点我们叫作套接字(socket)。
IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。 能够唯一标示网络中的进程后,它们就可以利用socket进行通信了
、
使用python内置的socket库,目前socket编程,最多是通过tcp协议进行网络通讯的。
tcp进行通讯的程序双方,分为服务端和客户端。
tcp协议进行通讯的双方,是需要先建立一个虚拟连接的,然后双方程序员才能发送业务数据信息。
服务端需要四个步骤:
1.新建socket
2.绑定IP和端口号
3.监听连接
4.收发消息
客户端需要三个步骤:
1.新建socket
2.连接服务器端
3.发收消息
服务端比客户端先运行,服务端先运行然后等待客户端连接
#TCP 服务端端程序 server.py #导入socket库 from socket import * #主机地址为0.0.0.0,表示绑定本机所有网络接口ip地址 #等待客户端来连接 IP='127.0.0.1' #端口号 PORT=50000 #定义一次从socket缓冲区最多读入512个字节数据 BUFLEN=512 #实例化一个socket对象 #参数 AF_INET 表示该socket网络层使用IP协议 #参数 SOCK_STREAM 表示该socket传输层使用tcp协议 listenSocket=socket(AF_INET,SOCK_STREAM) #socket绑定地址和端口 listenSocket.bind((IP,PORT)) #使socket处于监听状态,等待客户端的连接请求 #调用了.listen,就把socket置于等待连接状态 #参数5表示 最多接受多少个等待连接的客户端 listenSocket.listen(5) print(f'服务端启动成功,在{PORT}端口等待客户端连接...') #接收客户端连接,无客户端连接时,就处于睡眠状态 dataSocket,addr=listenSocket.accept() print('接受一个客户端连接:',addr) while True: #尝试读取对方发送的消息 #BUFLEN 指定从接收缓冲里最多读取多少字节 recved=dataSocket.recv(BUFLEN) #如果返回空bytes,表示对方关闭了连接 #退出循环,结束消息收发 if not recved: break #读取的学节数据是bytes类型,需要解码为字符串 info=recved.decode() print(f'收到对方信息:{info}') #发送的数据类型必须是bytes,所以要编码 dataSocket.send(f'服务端接收到了信息{info}'.encode()) #服务端也调用close()关闭socket dataSocket.close() listenSocket.close()
#TCP 客户端程序 client.py from socket import * IP='127.0.0.1' SERVER_PORT=50000 BUFLEN=512 #实例化一个socket对象,指明协议 dataSocket =socket(AF_INET,SOCK_STREAM) #连接服务端socket dataSocket.connect((IP,SERVER_PORT)) while True: #从终端读入用户输入的字符串 toSend =input('>>>') # 退出,跳出循环 if toSend =='exit': break #发送消息,也要编码为 bytes dataSocket.send(toSend.encode()) #等待接收服务段的消息,如果没有消息就一直等待 recved=dataSocket.recv(BUFLEN) #如果返回空bytes,表示对方关闭了连接 if not recved: break #打印读取的信息 print(recved.decode()) dataSocket.close()
运行代码之前,先查看的有没有处于50000的端口,然后执行server.py再查看端口,然后执行client.py再查看端口。
建立连接后,就能收发信息了
编程的时候,如果要跟某个IP建立连接,我们需要调用操作系统提供的 socket API。
socket 在操作系统层面,可以理解为一个文件。我们可以对这个文件进行一些方法操作。
- 用listen方法,可以让程序作为服务器监听其他客户端的连接。
- 用connect,可以作为客户端连接服务器。
- 用send或write可以发送数据,recv或read可以接收数据。
在建立好连接之后,如果我们想给远端服务发点什么东西,那就只需要对这个文件执行写操作就行了。
剩下的发送工作自然就是由操作系统内核来完成了。
既然是写给操作系统,那操作系统就需要提供一个地方给用户写。同理,接收消息也是一样。这个地方就是 socket 缓冲区。
- 用户发送消息的时候写给 send buffer(发送缓冲区)
- 用户接收消息的时候写给 recv buffer(接收缓冲区)
也就是说一个socket ,会带有两个缓冲区,一个用于发送,一个用于接收。因为这是个先进先出的结构,有时候也叫它们发送、接收队列。
在企业中开发的程序通信,消息往往有格式定义。消息的格式定义可以归入OSI中的表示层
比如:定义的消息,包括消息头和消息体。
消息头存放消息的数据格式(消息的长度、类型、状态等),消息体存放具体传送的数据。
对于TCP协议传输信息的程序来说,格式一定要有明确规定的消息边界。因为TCP传输的是字节流(bytes stream),如果消息中没有指定边界或者长度,接收方就不知道完整的消息从字节流的哪里开始,到哪里结束。
指定消息的边界有两种方式:
1.用特殊字节作为消息的结尾符号
可以用消息中不易出现的字符串(比如 FFFFFF)作为消息的结尾字符
2.在消息开头某个位置,直接指定消息的长度
UDP协议通常不用指定边界,因为UDP是数据报协议,应用程序从socket接收到的
必定是发送方发送的完整消息。{:.notice-info}