浅析python-socket编程
1. 什么是socket?
1. socket编程基本流程图

2. socket、threading实现聊天通信
# coding:utf-8
# 服务端: import socket
import threading HOST, PORT = "localhost",
address = (HOST, PORT) # socket.AF_INET代表IPV4, socket.AF_INET6代表IPV6
# socket.SOCK_STREAM代表TCP, SOCK_DGRAM代表UDP
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(address) server.listen() def handlesock(sock, addr):
while True:
data = sock.recv().decode("utf-8")
if data == "exit":
break
print("收到来自客户端[{0}]的消息, 内容是[{1}]".format(addr, data))
response = input("回复[{0}]:\t".format(addr)).encode("utf8")
sock.send(response) while True:
sock, addr = server.accept()
cur_sock = threading.Thread(target=handlesock, args=(sock, addr))
cur_sock.start()
# 客户端:
import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("localhost", )) while True:
response = input("回复服务器:").encode("utf8")
client.send(response)
if response=="exit":
break
data = client.recv().decode("utf8")
print("收到来自服务器的消息:%s" % data) client.close()
解释:对于单用户、单服务来说,一个服务器只服务一个用户对象, 那么要想实现两端通信, 能够通过循环来实现输入与输出;若是服务于多个用户对象, 就需要保留每一个连接(socket实例)对象来单独处理,这里我们采用了线程的方式,即每接收一个连接请求,就新开辟一个线程来处理(考虑到内存开销也可以用线程池来替代)。
3. socket模拟浏览器发送http请求
在此之前,我们必须弄懂相关概念,
###:socket并不是一种协议,而是对TCP/IP协议(或UDP/IP协议)的高级封装,其与TCP连接是可以存在包含关系的,换一句话说,socket就是一种通信接口,拥有实现可靠连接的功能。此外,当socket(网络套接字)采用TCP来建立连接的时候,是面向长连接的。
###:http连接显著的特点是客户端发送的每次请求都需要服务器回送相应响应,在请求结束后,会主动释放连接,从建立连接到关闭连接的过程称之为“一次连接”。此外HTTP连接是无状态的,所以在请求过程中需要发送请求头来标明请求身份。
(HTTP请求底层是一种特殊处理后的socket,是面向短连接的)
#coding:utf-8 from urllib.parse import urlparse
import socket class SocketHttp():
"""模拟http请求"""
def __init__(self, url: str):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.url = url def parse_url(self):
"""url解析"""
self.url = urlparse(self.url)
domain = self.url.netloc
path = self.url.path
if path == "":
path = "/"
return domain, path def request(self):
"""建立socket连接, 请求url"""
domain, path = self.parse_url()
self.client.connect((domain, 80))
request_data = """GET {0} HTTP/1.1\r\nHost: {1}\r\nConnection: close\r\n\r\n""".format(path, domain).encode("utf8")
self.client.send(request_data)
# 读取数据
response = b""
while True:
cur_data = self.client.recv(1024)
if cur_data:
response+=cur_data
else:
break
self.client.close()
return response.decode() if __name__ == '__main__':
client_http = SocketHttp("https://www.baidu.com/")
print(client_http.request())
输出:

我们也可以采用异步非阻塞IO来获取http响应
#coding:utf-8 from urllib.parse import urlparse
import socket class SocketHttp():
"""模拟http请求"""
def __init__(self, url: str):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.setblocking(False)
self.url = url def parse_url(self):
"""url解析"""
self.url = urlparse(self.url)
domain = self.url.netloc
path = self.url.path
if path == "":
path = "/"
return domain, path def request(self):
"""建立socket连接, 请求url"""
domain, path = self.parse_url()
try:
self.client.connect((domain, 80))
except BlockingIOError:
pass
request_data = """GET {0} HTTP/1.1\r\nHost: {1}\r\nConnection: close\r\n\r\n""".format(path, domain).encode("utf8") # 轮询尝试发送,直到与服务器连接成功
while 1:
try:
self.client.send(request_data)
except OSError as e:
pass
else:
break # 读取数据
response = b""
while True: # 不断轮询接收数据
while 1:
try:
cur_data = self.client.recv(1024)
except BlockingIOError as e:
pass
else:
break if cur_data:
response+=cur_data
else:
break
self.client.close()
return response.decode() if __name__ == '__main__':
client_http = SocketHttp("https://www.baidu.com/")
print(client_http.request())
异步非阻塞IO
4.非租塞IO
当两个通信实体成功建立连接之后,recv方法调用之后,其内核空间与应用空间的发生的数据复制行为如下

可以看出,若调用recv方法之后,数据未准备好, socket所处线程一直处于阻塞状态,直至数据复制到用户空间。这时,CPU未得到有效利用。那么如何才能利用起cpu资源呢?轮询方式便产生了(非阻塞I/O模式)
当线程执行recv方法时,不再让该线程睡眠,而是立即返回一个错误状态,以此不断轮询直到返回正确状态才退出循环,值得注意的是该轮询的方式需要我们手动实现。如下:

这里我们将客户端程序设置为非阻塞I/O模式,服务器程序不作修改,结果出现运行错误:


此处出错误是合理的,因为在非阻塞I/O模式下,模式发生改变,调用connnect方法便出现异常,此外,recv方法在调用时数据可能未准备好,所以这里需要手动实现轮询,如下:
import socket
import threading HOST, PORT = "localhost", 8020
address = (HOST, PORT) server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(address)
server.listen()
print("server is listening...")
def handlesock(sock, addr):
while True:
data = sock.recv(1024).decode("utf-8")
if data == "exit":
break
print("收到来自客户端[{0}]的消息, 内容是[{1}]".format(addr, data))
response = input("回复[{0}]:\t".format(addr)).encode("utf8")
sock.send(response) while True:
sock, addr = server.accept()
cur_sock = threading.Thread(target=handlesock, args=(sock, addr))
cur_sock.start()
服务端-阻塞式I/O
import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setblocking(0) try:
client.connect(("localhost", 8020))
except BlockingIOError:
pass while True:
response = input("回复服务器:").encode("utf8")
client.send(response)
if response=="exit":
break # 非阻塞I/O轮询方式
while True:
try:
data = client.recv(1024)
except BlockingIOError as e:
pass
else:
if data:
data = data.decode("utf8")
break print("收到来自服务器的消息:%s" % data) client.close()
客户端-非阻塞式I/O



浅析python-socket编程的更多相关文章
- Python Socket 编程——聊天室示例程序
上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...
- python/socket编程之粘包
python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...
- PYTHON SOCKET编程简介
原文地址: PYTHON SOCKET编程详细介绍 Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 Soc ...
- python socket编程笔记
用python实现一个简单的socket网络聊天通讯 (Linux --py2.7平台与windows--py3.6平台) 人生苦短之我用Python篇(socket编程) python之路 sock ...
- [Python_7] Python Socket 编程
0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*- "&q ...
- Python Socket 编程示例 Echo Server
简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通信方式,接下来让我们创建第一个客户端和服务器,我们将从一个简单的实现开始,服务器将简单 ...
- Python Socket 编程——聊天室演示样例程序
上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...
- python socket编程入门(编写server实例)+send 与sendall的区别与使用方法
python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...
- 第九章:Python高级编程-Python socket编程
第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...
- python socket编程详细介绍
Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...
随机推荐
- foundation-cli创建项目出错的解决方案
使用foundation-cli创建项目时,如果当前的node版本是12的话就会出现如下错误: fs.js:27 const { Math, Object } = primordials; ^ Ref ...
- 仿EXCEL插件,智表ZCELL产品V1.6 版本发布,增加自定义事件功能
详细请移步 智表(ZCELL)官网www.zcell.net 更新说明 这次更新主要应用户要求,主要解决了单元格值变化时事件的支持,并新增了按单元格名操作的相关API,欢迎大家体验使用. 本次版本更 ...
- uavcan扩展帧格式 zubax
zubax_gnss_1.0和zubax_gnss_2.0中使用的uavcan的两种不同封装方式.都是采用扩展帧29b帧类型 zubax_gnss_1.0 我的代码:https://github.co ...
- sqlite移植
编译 # tar xvf sqlite-3.6.16.tar.gz # cd sqlite-3.6.16 # ./configure # ./configure --host=arm-linux -- ...
- Availability-group DDL operations are permitted only when you are using the master database. Run the USE MASTER command, and retry your availability-group DDL command.
Question: SQL SERVER alwayson在向AG中添加DB最后一步在副本中将此DB添加入AG时报错: Availability-group DDL operations are p ...
- java安全相关知识
基本概念 JVM:java虚拟机,Java编译程序将生成Java虚拟机上可运行的目标代码,使得Java程序可以再不同平台不加修改的运行.JVM包含完善的硬件架构,主要分为五大模块-类装载器子系统.运行 ...
- 2013.6.26 - OpenNER第六天
今例会的时候看CRF,突然感觉到ANN模型可能没有问题了,问题出在评价函数,不能接过好就说好,或者说收敛方法有问题,并不是打得对就答得好.还有就是我们应该让他能够根据需要而自己产生问题,问我们,然后我 ...
- DateTimeFormatter LocalDateTime 工具类
import java.text.SimpleDateFormat; import java.time.Duration; import java.time.Instant; import java. ...
- django知识点回顾
1.web应用 本质是基于socket实现的应用程序 浏览器-----------服务器 2.http协议:应用层协议 1.基于TCP协议 2.基于请求响应 3.短连接 4.无状态保存(引入了cook ...
- Contest1063 - 2017广东工业大学第一次月赛-部分题解
Problem A: Chiruno Description 五年前,Aerix 无意间飞到了幻想乡,然后遇到了传说中的⑨酱,心情非常激动,想和她合影留念,但是⑨酱比较傲娇,她只欣赏算数能力强的,也不 ...