一、socket通信流程
1.什么是套接字(scoket)
套接字(scoket): 对网络中不同主机上的应用进程之间进行双向通信的端点的抽象
socket=(IP地址:端口号)
2.socket通信流程
客户端程序开发:
- 创建客户端套接字对象
socket.AF_INET IPV4 AF_INET6 ipv6 socket.SOCK_STREAM TCP协议
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- 和服务端套接字建立连接
tcp_client_socket.connect((host, port))
- 发送数据 二进制数据
message = ‘hello’
message = message.encode(‘utf-8’)
tcp_client_socket.send(message)
- 接收数据 最多接受1024个字节
tcp_client_socket.recv(1024)
- 关闭客户端套接字
tcp_client_socket.close()
服务端程序开发:
- 创建服务端端套接字对象
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
当客户端和服务端建立连接后,服务端程序退出后端口号不会立即释放,需要等待大概1-2分钟。
- 设置端口号复用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
- 绑定端口号 host不写,不固定,
tcp_server_socket.bind((host,port))
- 设置监听 backlog等待最大的连接数
tcp_server_socket.listen(backlog)
- 等待接受客户端的连接请求 返回新的套接字
tcp_client, port = tcp_server_socket.accept()
- 接收数据
tcp_client_socket.recv()
- 发送数据
tcp_client_socket.send()
- 关闭套接字
tcp_client.close() 进行通信
tcp_server_socket.close()
tcp_server_socket不进行通信,服务端套接字,被动套接字,只用与等待接受客户端的连接请求
二、同步阻塞(BIO)
- 服务端采用单线程,当 accept 一个请求后,在 recv 或 send 调用阻塞时,将无法 accept 其他请求(必须等上一个请求处理 recv 或 send 完 )(无法处理并发)
- 服务端采用多线程,当 accept 一个请求后,开启线程进行 recv,可以完成并发处理,但是,随着请求数增加需要增加系统线程,大量的线程占用很大的内存空间,并且线程切换会带来很大的开销,10000个线程真正发生读写实际的线程数不会超过20%,每次accept都开一个线程也是一种资源浪费。
python实现BIO的代码示例如下:
服务端:
import socket
import threading
def conn_client(server):
while True:
mesg = client.recv(1024)
if len(mesg) == 0:
break
print(mesg.decode())
send_msg = "hello111111111111"
client.send(send_msg.encode())
client.close()
if __name__ == '__main__':
# 创建服务端套接字
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 设置端口复用
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口号
server.bind(('**.*.**.**', 8000))
# 设置监听
server.listen(1024)
# 多客户端连接
while True:
client, port = server.accept()
thread = threading.Thread(target=conn_client, args=(client,))
thread.start()
server.close()
客户端:
import socket
if __name__ == '__main__':
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
client.connect(('**.*.**.**', 8000))
# mes = "hello"
while True:
mes = input("发送的数据:")
client.send(mes.encode())
mes1 = client.recv(1024)
print(mes1.decode())
client.close()