Socket TCP原语
用Socket进行网络开发需了解服务器和客户端的Socket原语,每个原语在不同的高级语言中都有相应的实现方式.
TCP的Socket原语,如图所示.所有基于TCP的Socket通信都遵循如图所示的流程,下面解释每个原语的含义.
- socket(): 建立Socket对象. Socket是以类似文件系统的‘打开、读写、关闭’的模式设计的,socket()原语相当于‘打开’. socket()原语的参数通常包括使用的传输层协议类型,网络层地址类型等.
- bind(): 绑定. 在参数中需要传入要绑定的IP地址和端口.IP地址必须是主机上的一个可用地址(0.0.0.0绑定所有的本机IP). 端口必须是一个未被占用的端口,服务端程序在listen()之前必须进行bind()操作,而客户端程序如果在connect()原语之前没有调用bind(),则系统会自动为该socket分配一个未被占用的地址和端口.
- listen(): 监听. 只在服务器端有用, 高速操作系统开始监听之前绑定IP地址和端口,可以在参数中指定允许排队的最大链接数量.
- connect(): 在客户端连接服务器.参数中需要指定服务器的地址和端口. 调用connect()可能有两种结果, 即与服务器端完成TCP3次握手并建立连接或者连接服务器失败.
- accept(): 接收连接. 只在服务器端有用, 从监听到的连接中取出一个,并将其包装成一个新的Socket对象. 这个新的Socket对象可被用于和相应的客户端进行通信. 完成accept()标志着Socket已经完成了TCP链路建立阶段的3次握手. 如果当前没有客户端连接请求, 则accep()调用会阻塞等待.
- send(): 发送数据. 服务器和客户端均可调用send()向对方发送数据, 在send()的参数中传入要发送的数据(字节),通过send()的返回值判断数据是否发送成功.
- recv(): 接收数据. 服务器和客户端均可调用recv()从对方接收数据. 如果Socket中没有消息可以读取,则在默认情况下recv()调用会被阻塞直到有消息到达; 开发者也可以将Socket设置为非阻塞模式, 使recv()以失败形式返回.
- close(): 关闭连接. 通信中的任何一方可以调用close()发起关闭连接请求, 另一方收到后也调用close()关闭连接.
下面是Python演示Socket的编程方法, TCP服务器端的代码如下:
# @Coding: utf-8 # @Time: 2021/8/3 3:13 import socket HOST = "0.0.0.0" PORT = 8080 def start_socket(host, port): so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 建立Socket连接, AF_INEF说明使用IPv4地址, SOCK_STREAM指明TCP协议 so.bind((host, port)) # 绑定IP和端口 so.listen(1) # 监听 while True: conn, addr = so.accept() # 接收TCP连接, 并返回新的Socket对象 print(f"Client: {addr} connected") # 打印客户端的IP message = "Connection Success" conn.send(message.encode('utf8')) # 向客户端发送当前的时间, send()函数接收的参数为bytes类型, data = conn.recv(1024) # 接收客户端发送的数据 print(data) conn.close() # 关闭连接 if __name__ == '__main__': start_socket(HOST, PORT)
TCP客户端对应的代码
# @Coding: utf-8 # @Time: 2021/8/3 3:45 下午 import socket HOST = '127.0.0.1' PORT = 8080 def init_socket(): so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) return so def connect_server(so, host, port, message): so.connect((host, port)) # 连接服务器端 data = so.recv(1024) # 接收数据 print(f"get message: {data}") so.send(f"{message}".encode('utf8')) # 发送数据 so.close() # 关闭连接 if __name__ == '__main__': connect_server(init_socket(), HOST, PORT, "Hello")
先运行server.py, 然后运行client.py 就可以看到client打印了 get message: b'Connection Success' 并退出. 服务器端打印 Client: ('127.0.0.1', 65358) connected b'Hello' 并阻塞
注意: 客户端的Socket端口号由系统自动分配