python Socket 之TCP

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端口号由系统自动分配

 

posted @ 2021-08-03 18:10  WenderWang  阅读(1520)  评论(0编辑  收藏  举报