1. 什么是socket?

  socket是套接字的英文名称, 我们知道在TCP/IP协议簇体系中,将网络状态分为了应用层、传输层、网络层、物理层等四种状态,而socket是与传输层密切相关的,其主要实现协议为TCP及UDP。传输层实现端到端的通信,因此,每一个传输层连接有两个端点。那么,传输层连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口。传输层连接的端点叫做套接字(socket)。根据RFC793的定义:端口号拼接到IP地址就构成了套接字。所谓套接字,实际上是一个通信端点,每个套接字都有一个套接字序号,包括主机的IP地址与一个16位的主机端口号,即形如(主机IP地址:端口号)。例如,如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23)。
总之,套接字Socket=(IP地址:端口号),套接字的表示方法是点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。每一个传输层连接唯一地被通信两端的两个端点(即两个套接字)所确定。
套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到其他程序中。因此,两个应用程序之间的数据传输要通过套接字来完成。
在网络应用程序设计时,由于TCP/IP的核心内容被封装在操作系统中,如果应用程序要使用TCP/IP,可以通过系统提供的TCP/IP的编程接口来实现。在Windows环境下,网络应用程序编程接口称作Windows Socket。为了支持用户开发面向应用的通信程序,大部分系统都提供了一组基于TCP或者UDP的应用程序编程接口(API),该接口通常以一组函数的形式出现,也称为套接字(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编程的更多相关文章

  1. Python Socket 编程——聊天室示例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和客户端的代码了解基本的 Python Socket 编程模型.本文再通过一个例子来加强一下对 Socket 编程的 ...

  2. python/socket编程之粘包

    python/socket编程之粘包 粘包 只有TCP有粘包现象,UDP永远不会粘包. 首先需要掌握一个socket收发消息的原理 发送端可以是1k,1k的发送数据而接受端的应用程序可以2k,2k的提 ...

  3. PYTHON SOCKET编程简介

    原文地址: PYTHON SOCKET编程详细介绍   Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 Soc ...

  4. python socket编程笔记

    用python实现一个简单的socket网络聊天通讯 (Linux --py2.7平台与windows--py3.6平台) 人生苦短之我用Python篇(socket编程) python之路 sock ...

  5. [Python_7] Python Socket 编程

    0. 说明 Python Socket 编程 1. TCP 协议 [TCP Server] 通过 netstat -ano 查看端口是否开启 # -*-coding:utf-8-*- "&q ...

  6. Python Socket 编程示例 Echo Server

    简评:我们已经从「Python Socket 编程概览」了解了 socket API 的概述以及客户端和服务器的通信方式,接下来让我们创建第一个客户端和服务器,我们将从一个简单的实现开始,服务器将简单 ...

  7. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  8. python socket编程入门(编写server实例)+send 与sendall的区别与使用方法

    python 编写server的步骤: 1. 第一步是创建socket对象.调用socket构造函数.如: socket = socket.socket( family, type ) family参 ...

  9. 第九章:Python高级编程-Python socket编程

    第九章:Python高级编程-Python socket编程 Python3高级核心技术97讲 笔记 9.1 弄懂HTTP.Socket.TCP这几个概念 Socket为我们封装好了协议 9.2 cl ...

  10. python socket编程详细介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

随机推荐

  1. 禁止迅雷极速版被强制升级为迅雷x

    PS:迅雷极速版( ThunderSpeed1.0.34.360 )下载地址: https://pan.baidu.com/s/1wuBOpNbim5jBru03AfSAVg 按照下面的这个路径去找. ...

  2. CSS是什么

    css是层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文件样式的计算机语言. CSS不 ...

  3. 删除Ubuntu的UEFI启动项

    bcdedit 删除 千万不要手贱用diskpart之类的命令直接删除文件夹,大写的没,有,用! 感谢这个视频的up主,youtube看不到请翻墙.https://www.youtube.com/wa ...

  4. python相关软件安装

    一. python 3 安装 Python官网 在官网下载对应系统的安装包 安装步骤 注意:有的时候安装完后会出现"Disable path length limit"的按钮,如果 ...

  5. 【hbase】hbase的shell操作笔记

    HBase Shell $ ./bin/hbase shell # 进入交互界面 DDL操作: create:创建表(默认命名空间为default) # create '表名','列族1','列族2' ...

  6. 部署python项目到linux服务器

    最近用Python写了个外挂,需要部署到Linux环境的服务器上,由于之前本地开发时使用virtualenv,使用这个虚拟环境有个好处是项目中依赖的库不会是全局的,只在当前项目的目录下有效,因为我是M ...

  7. Qt5安装及组件选择(Qt 5.12.0)

    组件选择 如下图所示,安装Qt时有选择组件这一步,全部安装未免太占磁盘控件,只需安装我们所需要的组件即可.接下来就分析分析各个组件的作用及含义. “Qt 5.12.0”节点下面是 Qt 的功能模块,包 ...

  8. 右键tomcat找不到项目:There are no resources that can be added or removed from the server.

    右键Add and Remove找不到项目,会出现下面这个弹框: 之后在项目文件夹上右键(Java Build Path中引用的jdk的版本也需要和下面这个Project Facets中配置的java ...

  9. 介绍一个二次排序的小技巧(best coder27期1001jump jump jump)

    先来描述一下问题: 问题描述 有n小孩在比赛跳远,看谁跳的最远.每个小孩可以跳3次,这个小孩的成绩就是三次距离里面的最大值.例如,一个小孩跳3次的距离分别时10, 30和20,那么这个小孩的成绩就是3 ...

  10. Vue移动组件库Mint UI的安装与使用

    一.什么是 Mint UI 1.Mint UI 包含丰富的 CSS 和 JS 组件,可以提升移动端开发效率 2.Mint UI 按需加载组件 3.Mint UI 轻量化 二.Mint UI 的安装 1 ...