日期: 2021 年 5 月 10 日

Python之Pandas学习

Python之Pandas学习

一、Pandas
pandas是python+data+analysis的组合缩写,2008年WesMcKinney开发出的库,专门用于数据挖掘的开源Python库,是python中基于numpy和matplotlib的第三方数据分析库,与后两者共同构成了python数据分析的基础工具包,享有数分三剑客之名。
pandas是在numpy基础上实现,其核心数据结构与numpy的ndarray十分相似,但pandas与numpy的关系不是替代,而是互为补充。

二者之间主要区别是:

1.数据结构上:
numpy的核心数据结构是ndarray,支持任意维数的数组,但要求单个数组内所有数据是同质的,即类型必须相同;而pandas的核心数据结构是series和dataframe,仅支持一维和二维数据,但数据内部可以是异构数据,仅要求同列数据类型一致即可
numpy的数据结构仅支持数字索引,而pandas数据结构则同时支持数字索引和标签索引

2.功能定位上:
numpy虽然也支持字符串等其他数据类型,但仍然主要是用于数值计算,尤其是内部集成了大量矩阵计算模块,例如基本的矩阵运算、线性代数、fft、生成随机数等,支持灵活的广播机制
pandas主要用于数据处理与分析,支持包括数据读写、数值计算、数据处理、数据分析和数据可视化全套流程操作

pandas主要面向数据处理与分析,主要具有以下功能特色:

按索引匹配的广播机制,这里的广播机制与numpy广播机制还有很大不同
便捷的数据读写操作,相比于numpy仅支持数字索引,pandas的两种数据结构均支持标签索引,包括bool索引也是支持的
类比SQL的join和groupby功能,pandas可以很容易实现SQL这两个核心功能,实际上,SQL的*大部分DQL和DML操作在pandas中都可以实现
类比Excel的数据透视表功能,Excel中*为强大的数据分析工具之一是数据透视表,这在pandas中也可轻松实现
自带正则表达式的字符串向量化操作,对pandas中的一列字符串进行通函数操作,而且自带正则表达式的大部分接口
丰富的时间序列向量化处理接口
常用的数据分析与统计功能,包括基本统计量、分组统计分析等
集成matplotlib的常用可视化接口,无论是series还是dataframe,均支持面向对象的绘图接口
核心数据结构
1、DataFrame

既有行索引,又有列索引的二维数组
行索引,表明不同行,横向索引,叫index
列索引,表明不同列,纵向索引,叫columns
常用属性

shape
index 行索引列表
columns 列索引列表
values 直接获取其中array的值
T 行列转置
常用方法

head() 开头几行
tail() *后几行
import numpy as np
import pandas as pd
# 创建一个符合正态分布的10个股票5天的涨跌幅数据
stock_change = np.random.normal(0, 1, (10, 5))
pd.DataFrame(stock_change)
# 添加行索引
stock = [“股票{}”.format(i) for i in range(10)]
pd.DataFrame(stock_change, index=stock)
# 添加列索引
date = pd.date_range(start=”20200101″, periods=5, freq=”B”)
data = pd.DataFrame(stock_change, index=stock, columns=date)

# 属性
print(data.shape)
print(data.index)
print(data.columns)
print(data.values)
data.T # 行列转置

# 方法
data.head(3) # 开头3行
data.tail(2) # *后2行

索引设置

# 修改行列索引值
# data.index[2] = “股票88” 不能单独修改索引
stock_ = [“股票_{}”.format(i) for i in range(10)]
data.index = stock_

# 重设索引
data.reset_index(drop=False) # drop=True把之前的索引删除

# 设置新索引
df = pd.DataFrame({‘month’: [1, 4, 7, 10],
‘year’: [2012, 2014, 2013, 2014],
‘sale’:[55, 40, 84, 31]})
# 以月份设置新的索引
df.set_index(“month”, drop=True)
# 设置多个索引,以年和月份
new_df = df.set_index([“year”, “month”])

2、MultiIndex与Panel

2.1、MultiIndex
多级或分层索引对象

index属性
names: levels的名称
levels: 每个level的元组值
print(new_df.index)
print(new_df.index.names)
print(new_df.index.levels)

2.2、Panel

pandas.Panel(data=None,items=None,major_axis=None,minor_axis=None,copy=False,dtype=None)存储3维数组的Panel结构

items – axis 0,每个项目对应于内部包含的数据帧(DataFrame)。
major_axis – axis 1,它是每个数据帧(DataFrame)的索引(行)。
minor_axis – axis 2,它是每个数据帧(DataFrame)的列。
p = pd.Panel(np.arange(24).reshape(4,3,2),
items=list(‘ABCD’),
major_axis=pd.date_range(‘20130101’, periods=3),
minor_axis=[‘first’, ‘second’])
p[“A”]
p.major_xs(“2013-01-01”)
p.minor_xs(“first”)

注:Pandas从版本0.20.0开始弃用,推荐的用于表示3D数据的方法是DataFrame上的MultiIndex方法

3、Series
带索引的一维数组

属性

index
values
# 创建
pd.Series(np.arange(3, 9, 2), index=[“a”, “b”, “c”])
# 或
pd.Series({‘red’:100, ‘blue’:200, ‘green’: 500, ‘yellow’:1000})

sr = data.iloc[1, :]
sr.index # 索引
sr.values # 值

总结:DataFrame是Series的容器,Panel是DataFrame的容器

二、基本数据操作
1、索引操作
data = pd.read_csv(“./stock_day/stock_day.csv”)
data = data.drop([“ma5″,”ma10″,”ma20″,”v_ma5″,”v_ma10″,”v_ma20”], axis=1) # 去掉一些不要的列
data[“open”][“2018-02-26”] # 直接索引,先列后行

data.loc[“2018-02-26”][“open”] # 按名字索引
data.loc[“2018-02-26”, “open”]
data.iloc[1, 0] # 数字索引

# 组合索引
# 获取行第1天到第4天,[‘open’, ‘close’, ‘high’, ‘low’]这个四个指标的结果
data.iloc[:4, [‘open’, ‘close’, ‘high’, ‘low’]] # 不能用了
data.loc[data.index[0:4], [‘open’, ‘close’, ‘high’, ‘low’]]
data.iloc[0:4, data.columns.get_indexer([‘open’, ‘close’, ‘high’, ‘low’])]

2、赋值操作
data.open = 100
data.iloc[1, 0] = 222
1
2
3、排序操作
排序有两种形式,一种对内容进行排序,一种对索引进行排序

内容排序:
使用df.sort_values(key=,ascending=)对内容进行排序,单个键或者多个键进行排序,默认升序,ascending=False:降序 True:升序
索引排序:
使用df.sort_index对索引进行排序
data.sort_values(by=”high”, ascending=False) # DataFrame内容排序

data.sort_values(by=[“high”, “p_change”], ascending=False).head() # 多个列内容排序

data.sort_index().head()

sr = data[“price_change”]

sr.sort_values(ascending=False).head()

sr.sort_index().head()

三、DataFrame运算
1、算术运算
data[“open”].add(3).head() # open统一加3 data[“open”] + 3
data.sub(100).head() # 所有统一减100 data – 100
data[“close”].sub(data[“open”]).head() # close减open

2、逻辑运算
query(expr) expr:查询字符串
isin(values) 判断是否为values

data[data[“p_change”] > 2].head() # p_change > 2
data[(data[“p_change”] > 2) & (data[“low”] > 15)].head()

data.query(“p_change > 2 & low > 15”).head()

# 判断’turnover’是否为4.19, 2.39
data[data[“turnover”].isin([4.19, 2.39])]

3、统计运算
describe()

综合分析:能够直接得出很多统计结果,count,mean,std,min,max等

data.describe()
data.max(axis=0)
data.idxmax(axis=0) #*大值位置

4、累计统计函数
cumsum 计算前1/2/3/…/n个数的和
cummax 计算前1/2/3/…/n个数的*大值
cummin 计算前1/2/3/…/n个数的*小值
cumprod 计算前1/2/3/…/n个数的积

data[“p_change”].sort_index().cumsum().plot()
1
5、自定义运算
apply(func, axis=0)
func: 自定义函数
axis=0: 默认按列运算,axis=1按行运算

data.apply(lambda x: x.max() – x.min())
1

四、Pandas画图
pandas.DataFrame.plot
DataFrame.plot(x=None, y=None, kind=‘line’)

x: label or position, default None
y: label, position or list of label, positions, default None
Allows plotting of one column versus another
kind: str
‘line’: line plot(default)
-’’bar”: vertical bar plot
-“barh”: horizontal bar plot
-“hist”: histogram
-“pie”: pie plot
-“scatter”: scatter plot
data.plot(x=”volume”, y=”turnover”, kind=”scatter”)
data.plot(x=”high”, y=”low”, kind=”scatter”)
1
2
pandas.Series.plot

sr.plot(kind=”line”)
1

五、文件读取与存储(常用3种文件类型)
1、CSV
pd.read_csv(“./stock_day/stock_day.csv”, usecols=[“high”, “low”, “open”, “close”]).head() # 读哪些列

data = pd.read_csv(“stock_day2.csv”, names=[“open”, “high”, “close”, “low”, “volume”, “price_change”, “p_change”, “ma5”, “ma10”, “ma20”, “v_ma5”, “v_ma10”, “v_ma20”, “turnover”]) # 如果列没有列名,用names传入

data[:10].to_csv(“test.csv”, columns=[“open”]) # 保存open列数据

data[:10].to_csv(“test.csv”, columns=[“open”], index=False, mode=”a”, header=False) # 保存opend列数据,index=False不要行索引,mode=”a”追加模式|mode=”w”重写,header=False不要列索引

2、HDF5
read_hdf()与to_hdf()
HDF5文件的读取和存储需要指定一个键,值为要存储的DataFrame
pandas.read_hdf(path_or_buf, key=None, **kwargs)

从h5文件当中读取数据

path_or_buffer: 文件路径
key: 读取的键
mode: 打开文件的模式
reurn: The Selected object
DataFrame.to_hdf(path_or_buf, key, **kwargs)

day_close = pd.read_hdf(“./stock_data/day/day_close.h5”)
day_close.to_hdf(“test.h5″, key=”close”)

3、JSON
read_json()

pandas.read_json(path_or_buf=None,orient=None,typ=“frame”,lines=False)

将JSON格式转换成默认的Pandas DataFrame格式
orient: string,Indication of expected JSON string format.
‘split’: dict like {index -> [index], columns -> [columns], data -> [values]}
‘records’: list like [{column -> value}, …, {column -> value}]
‘index’: dict like {index -> {column -> value}}
‘columns’: dict like {column -> {index -> value}}, 默认该格式
‘values’: just the values array
lines: boolean, default False
按照每行读取json对象
typ: default ‘frame’,指定转换成的对象类型series或者dataframe
sa = pd.read_json(“Sarcasm_Headlines_Dataset.json”, orient=”records”, lines=True)

sa.to_json(“test.json”, orient=”records”, lines=True)

六、缺失值处理
如何进行缺失值处理?

删除含有缺失值的样本
替换/插补数据
1、如何处理NaN?
1.1、判断是否有NaN

pd.isnull(df)
pd.notnull(df)
1.2、删除含有缺失值的样本
df.dropna(inplace=True) 默认按行删除 inplace:True修改原数据,False返回新数据,默认False
1.3、替换/插补数据
df.fillna(value,inplace=True) value替换的值 inplace:True修改原数据,False返回新数据,默认False

import pandas as pd
import numpy as np
movie = pd.read_csv(“./IMDB/IMDB-Movie-Data.csv”)
# 1)判断是否存在NaN类型的缺失值
np.any(pd.isnull(movie)) # 返回True,说明数据中存在缺失值
np.all(pd.notnull(movie)) # 返回False,说明数据中存在缺失值
pd.isnull(movie).any()
pd.notnull(movie).all()

# 2)缺失值处理
# 方法1:删除含有缺失值的样本
data1 = movie.dropna()
pd.notnull(data1).all()

# 方法2:替换
# 含有缺失值的字段
# Revenue (Millions)
# Metascore
movie[“Revenue (Millions)”].fillna(movie[“Revenue (Millions)”].mean(), inplace=True)
movie[“Metascore”].fillna(movie[“Metascore”].mean(), inplace=True)

2、不是缺失值NaN
不是缺失值NaN,有默认标记的

# 读取数据
path = “https://archive.ics.uci.edu/ml/machine-learning-databases/breast-cancer-wisconsin/breast-cancer-wisconsin.data”
name = [“Sample code number”, “Clump Thickness”, “Uniformity of Cell Size”, “Uniformity of Cell Shape”, “Marginal Adhesion”, “Single Epithelial Cell Size”, “Bare Nuclei”, “Bland Chromatin”, “Normal Nucleoli”, “Mitoses”, “Class”]

data = pd.read_csv(path, names=name)

# 1)替换
data_new = data.replace(to_replace=”?”, value=np.nan)

# 2)删除缺失值
data_new.dropna(inplace=True)

七、数据离散化
连续属性的离散化就是将连续属性的值域上,将值域划分为若干个离散的区间,*后用不同的符号或整数 值代表落在每个子区间的属性值。

为什么要离散化:
连续属性离散化的目的是为了简化数据结构,数据离散化技术可以用来减少给定连续属性值的个数。离散化方法经常作为数据挖掘的工具。

如何实现数据的离散化
1、分组

自动分组 sr = pd.qcut(data, bins)
自定义分组 sr = pd.cut(data, [])
2、将分组好的结果转换成one-hot编码(哑变量)

pd.get_dummies(sr, prefix=)
# 1)准备数据
data = pd.Series([165,174,160,180,159,163,192,184], index=[‘No1:165’, ‘No2:174′,’No3:160’, ‘No4:180’, ‘No5:159’, ‘No6:163’, ‘No7:192’, ‘No8:184’])
# 2)分组
# 自动分组
sr = pd.qcut(data, 3)
sr.value_counts() # 看每一组有几个数据
# 3)转换成one-hot编码
pd.get_dummies(sr, prefix=”height”)

# 自定义分组
bins = [150, 165, 180, 195]
sr = pd.cut(data, bins)
# get_dummies
pd.get_dummies(sr, prefix=”身高”)

八、合并
1、按方向
pd.concat([data1, data2], axis=1) axis:0为列索引;1为行索引

2、按索引
pd.merge(left, right, how=“inner”, on=[]) on:索引

left = pd.DataFrame({‘key1’: [‘K0’, ‘K0’, ‘K1’, ‘K2’],
‘key2’: [‘K0’, ‘K1’, ‘K0’, ‘K1’],
‘A’: [‘A0’, ‘A1’, ‘A2’, ‘A3’],
‘B’: [‘B0’, ‘B1’, ‘B2’, ‘B3’]})

right = pd.DataFrame({‘key1’: [‘K0’, ‘K1’, ‘K1’, ‘K2’],
‘key2’: [‘K0’, ‘K0’, ‘K0’, ‘K0’],
‘C’: [‘C0’, ‘C1’, ‘C2’, ‘C3’],
‘D’: [‘D0’, ‘D1’, ‘D2’, ‘D3’]})

pd.merge(left, right, how=”inner”, on=[“key1”, “key2″])

pd.merge(left, right, how=”left”, on=[“key1”, “key2″])

pd.merge(left, right, how=”outer”, on=[“key1”, “key2”])

九、交叉表与透视表
找到、探索两个变量之间的关系

1、交叉表
交叉表用于计算一列数据对于另外一列数据的分组个数(寻找两个列之间的关系)

pd.crosstab(value1, value2)

data = pd.crosstab(stock[“week”], stock[“pona”])
data.div(data.sum(axis=1), axis=0).plot(kind=”bar”, stacked=True)

2、透视表
DataFrame.pivot_table([], index=[])

# 透视表操作
stock.pivot_table([“pona”], index=[“week”])

十、分组与聚合
分组与聚合通常是分析数据的一种方式,通常与一些统计函数一起使用,查看数据的分组情况。
DataFrame.groupby(key, as_index=False) key:分组的列数据,可以多个

col =pd.DataFrame({‘color’: [‘white’,’red’,’green’,’red’,’green’], ‘object’: [‘pen’,’pencil’,’pencil’,’ashtray’,’pen’],’price1′:[5.56,4.20,1.30,0.56,2.75],’price2′:[4.75,4.12,1.60,0.75,3.15]})

# 进行分组,对颜色分组,price1进行聚合
# 用dataframe的方法进行分组
col.groupby(by=”color”)[“price1”].max()

# 或者用Series的方法进行分组聚合
col[“price1”].groupby(col[“color”]).max()

浏览器和服务器的区别

javase中用的tomcat就是一个服务器
简单来说,浏览器是网站访问者使用的,服务器是网站管理者使用的

两者具体的区别:
一、指代不同

1、浏览器:用来显示在万维网或局域网等内的文字、图像及其他信息的软件。

2、Web服务器:也称为WWW(WORLD WIDE WEB)服务器,主要功能是提供网上信息浏览服务。

二、功能不同

1、浏览器:度用户可以通过在地址栏中键入常用的地址来访问网页。如果有误,浏览器会自动搜索类似的地址找出匹配的地址。

2、Web服务器:可以解析(handles)HTTP协议。当Web服务器接收到一个HTTP请求(request),会返回一个HTTP响应(response),例如送回一个HTML页面。

三、特点不同

1、浏览器:是Internet时代的产物,随着电脑操作系统的普权及、Internet的全球连接及人们对信息需求的爆炸式增长,为浏览器的诞生和兴起提供了强大的动力,同时它也标志着互联网时代的来临。

2、Web服务器:Web服务器传送(serves)页面使浏览器可以浏览,然而应用程序服务器提供的是客户端应用程序可以调用(call)的方法(methods)。

浏览器页面之间进行通信的四种方式

1、localStorage

一个窗口更新localStorage,另一个窗口监听window对象的”storage”事件,来实现通信。
注:两个页面要同源(URL的协议、域名和端口相同)

%title插图%num

2、cookie+setInterval()
page1将要传递的信息存储在cookie中,page2使用setInterval每隔一定时间读取cookie信息,即可随时获取要传递的信息。

3、postMessage
html5引入了一个跨文档通信的API,这个API为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。
该方法只解决了前端两个窗口的通信,但无法解决前后台调用的跨域问题。使用 window.postMessage(),就注定了你首先得拿到window这个对象。 也注定他使用的限制, 两个窗体必须建立起联系。 常见建立联系的方式: window.open、 window.opener、iframe

4、WebSocket 服务器中转
需要页面都与服务器建立 WebSockets 连接;支持跨域;
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。在WebSocket API中,浏览器和服务器只需要做一个握手的动作,两者之间就直接可以数据互相传送。你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

diy数据库(八)–客户端和服务器之间的通信协议

一、什么是通信协议

通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。

二、diydb的协议格式

1、协议格式是通信协议中*重要的部分之一,diydb采用的是自定义格式和BSON格式的混合格式

2、协议格式总览

%title插图%num

协议主要分三个大段

(1)协议头:包括消息长度(用于读取一个完整的协议包)和消息类型

(2)协议主体:不同的消息类型对应不同的协议主体,协议主体主要保存的是每种消息类型独有的信息

(3)附加信息:一个或多个bson格式的对象,表示实际操作和返回的数据库中的数据对象

3、协议格式主体

%title插图%num

返回消息:一、返回值,用于表示返回成功或失败;二、返回记录数,用于表示返回的数据对象的个数,即附加消息中bson对象的个                     数。

插入消息:插入记录数,表示要插入的数据对象的个数。

删除消息:因为每次只能删除一个数据,所以这里没有特殊信息。

查询消息:因为每次只能查询一个数据,所以这里没有特殊信息。

注:1)diydb的数据删除和查询时,客户端必须在附加信息中以bson格式传递一个数据对象的_id信息。

2)另外,quit命令只需要协议头就可以了。

4、附加信息

%title插图%num

每个附加记录或插入记录实际上就是一个bson对象,删除条件或查询条件实际上就是{_id:XXX}格式的json对象对应的bson对象(因为diydb实际上没有复杂的条件查询功能,当然可以以后增加)。

注:1)、在直接传递一个结构体对象时,要注意结构体里面的属性的字节对齐。

2)、跨操作系统通信时要注意字节序的问题。

三、源码分析

通讯协议的主要实现(这里主要是数据打包解包)在msg.hpp和msg.cpp两个文件中,比如客户端用msgBuildInsert封装表示插入数据的数据包并存入数据流中,然后服务器端代理线程收到这个数据流后用msgExtractInsert解包这个数据流中的数据。下面是msg.hpp的所有代码。

#ifndef MSG_HPP__
#define MSG_HPP__

#include “bson.h”

#define OP_REPLY 1//返回消息
#define OP_INSERT 2//插入消息
#define OP_DELETE 3//删除消息
#define OP_QUERY 4//查询消息
#define OP_DISCONNECT 6//断开连接消息
#define OP_CONNECT 7//连接消息

#define RETURN_CODE_STATE_OK 1

struct MsgHeader
/*数据包的头*/
{
int messageLen ;//数据包的长
int opCode ;//数据包类型
} ;

struct MsgReply
/*返回数据包*/
{
MsgHeader header ;//数据包的头
int returnCode ;//返回值
int numReturn ;//返回的记录数量
char data[0] ;//标记数具体的开始位置
} ;

struct MsgInsert
/*插入数据包*/
{
MsgHeader header ;
int numInsert ;//插入记录数
char data[0] ;
} ;

struct MsgDelete
/*删除数据包*/
{
MsgHeader header ;
char key[0] ;//删除条件
} ;

struct MsgQuery
/*查询数据包*/
{
MsgHeader header ;
char key[0] ;//查询条件
} ;

/*返回消息的封装*/
int msgBuildReply ( char **ppBuffer, int *pBufferSize,
int returnCode, bson::BSONObj *objReturn ) ;

/*解消息*/
int msgExtractReply ( char *pBuffer, int &returnCode, int &numReturn,
const char **ppObjStart ) ;

/*做一个插入obj的数据包*/
int msgBuildInsert ( char **ppBuffer, int *pBufferSize, bson::BSONObj &obj ) ;

/*做一个插入多个obj的数据包*/
int msgBuildInsert ( char **ppBuffer, int *pBufferSize, vector<bson::BSONObj*> &obj ) ;

/*解插入*/
int msgExtractInsert ( char *pBuffer, int &numInsert, const char **ppObjStart ) ;

/*删除*/
int msgBuildDelete ( char **ppBuffer, int *pBufferSize, bson::BSONObj &key ) ;

/*解删除*/
int msgExtractDelete ( char *pBuffer, bson::BSONObj &key ) ;

/*查询*/
int msgBuildQuery ( char **ppBuffer, int *pBufferSize, bson::BSONObj &key ) ;

/*解查询*/
int msgExtractQuery ( char *pBuffer, bson::BSONObj &key ) ;

int msgMultiInsert ( char **ppBuffer, int *pBufferSize, bson::BSONObj &obj ) ;

/*做一个插入多个obj的数据包*/
int msgBuildInsert ( char **ppBuffer, int *pBufferSize, vector<bson::BSONObj*> &obj ) ;

#endif

对上面函数的实现,我们以插入数据包的封装和解包为例来分析

int msgBuildInsert ( char **ppBuffer, int *pBufferSize, BSONObj &obj )
{//只插入一个数据
int rc = DIY_OK ;
int size = sizeof(MsgInsert) + obj.objsize() ;//表示插入数据的数据包的长度
MsgInsert *pInsert = NULL ;
rc = msgCheckBuffer ( ppBuffer, pBufferSize, size ) ;//如果*ppBuffer指向的堆空间不够用,则重新分配一个足够的字节数组空间
if ( rc )
{
PD_LOG ( PDERROR, “Failed to realloc buffer for %d bytes, rc = %d”,
size, rc ) ;
goto error ;
}

pInsert = (MsgInsert*)(*ppBuffer) ;//将字节流划分成包格式
// 构建协议头
pInsert->header.messageLen = size ;
pInsert->header.opCode = OP_INSERT ;
// 构建协议主体
pInsert->numInsert = 1 ;
// 构建附加消息,即填bson对象
memcpy ( &pInsert->data[0], obj.objdata(), obj.objsize() ) ;
done :
return rc ;
error :
goto done ;
}

int msgExtractInsert ( char *pBuffer, int &numInsert, const char **ppObjStart )
{
int rc = DIY_OK ;
MsgInsert *pInsert = (MsgInsert*)pBuffer ;
// 检测数据包的长度是否合法
if ( pInsert->header.messageLen < (int)sizeof(MsgInsert) )
{
PD_LOG ( PDERROR, “Invalid length of insert message” ) ;
rc = DIY_INVALIDARG ;
goto error ;
}
// 检测数据包的类型对不对
if ( pInsert->header.opCode != OP_INSERT )
{
PD_LOG ( PDERROR, “non-insert code is received: %d, expected %d”,
pInsert->header.opCode, OP_INSERT ) ;
rc = DIY_INVALIDARG ;
goto error ;
}
// 解析附加信息,即取出bson对象
numInsert = pInsert->numInsert ;
// object
if ( 0 == numInsert )
{
*ppObjStart = NULL ;
}
else
{
*ppObjStart = &pInsert->data[0] ;
}
done :
return rc ;
error :
goto done ;
}
注:客户端得到的bson对象的由来:用户在客户端输入命令,这个命令如果包含json格式的文本,则通过json库根据表示json格式的文本构建一个json对象,然后通过bson库将这个json对象转换成一个bson对象。

四、总结

1、因为tcp通信是字节流,并没有边界标识,所以应用层在传数据时,必须通过增加数据包长度字段或者增加数据包边界标识来区分一个完整的包。diydb中用的是数据包长度的方式,这也是实际应用中常用的方式。
2、如果在通信时直接传结构体数据,则要注意字节对齐机制,所以要合理安排结构体中属性的长度的排列顺序。

 

浏览器 服务器之间的通信过程

B/S(Browser/Server)结构就是浏览器/服务器结构,它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,*少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。本文将主要讲解浏览器和服务器通信的过程。

浏览器和服务器之间的通讯并不是看上去那么简单,里面还是有着许多的门道的。想要简单理解浏览器和服务器之间的通讯,我们可以打一个简单的比方:

设想我们自己就是浏览器,服务器就是10086语音服务台,我们现在想要和10086服务台取得联系(比如说想骚扰接线员MM),我们该怎么办呢?

当然,大多数人都应该想到,那就是要有部电话。是这样的,这就引出了我们的*个概念:套接字(Socket)。

套接字在百度百科上的解释是:

多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。

这个解释太学术了,我们可以简单把套接字理解成一个电话,我们可以从中发送信息和获取信息。

好了,电话有了,我们该给10086服务台打电话了。等等,我们是不是忘了一点,给10086打电话是不是要保证10086服务台也要有一部电话来等待我们的来电呢?对的,那么就是说服务器端也要有一个套接字,专门接受浏览器的请求。一般当一个服务器启动服务后就会开启一个监听连接的套接字,专门等待浏览器连接,接受浏览器请求。

接下来我们要开始打电话了。大多数人都应该有给10086服务台打电话的经验吧,接通后并不是马上由接线员MM来接听你的电话的,而是根据语音提示选择你想要的服务。当你选择了语音服务以后,系统才会自动给你安排一个接线员MM来接听你的电话。那么这个过程是不是又生成了一个套接字呢?是的,没错,我们可以把呼叫系统(也就是给你语音提示,让你选择服务的系统)当成专门接受浏览器的请求的那个套接字,当浏览器发送了一个请求后系统自动生成一个专门和你的浏览器通信的套接字,这样我们就可以和接线员MM通话了,浏览器也就可以和服务器通信了。

当然这远远不是B/S结构的全部,我们还需要进一步深化:

首先我们想想,我们要和接线员通话是不是要约定一个大家都能听得懂的语言,否则我说中文他说英语,这样就谁也听不懂谁的话,也不会完成通话,那么这个约定的语言是什么呢?那就是HTTP协议。

还是先来看百度百科上的解释:

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用*为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP*初的目的是为了提供一种发布和接收HTML页面的方法。

我们就可以把它理解成一种浏览器和服务器都遵循的一种语法规范,所有的信息都是通过这种语法规范传输的,这样浏览器和服务器都可以正确的理解。

浏览器和服务器一般并不是直接连接上的,而是需要通过中间的网络设备,就像我们的声音并不是直接传到接线员的耳朵里,而是要通过电话线通过电波传送一样,浏览器和服务器所发送的遵循HTTP协议的信息也要通过网络设备的传递才能被对方所接收。而这就需要一种在网络设备(网线)上传输数据的一种通用的语法规范(协议)。这样的协议使用*多的有2种:TCP协议和UDP协议

TCP—传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

UDP—用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

不管使用哪种方法,总之这样网络设备间也有了一套传输的协议,这样一来,浏览器和服务器才能真正的实现通信。

下面让我们来看看我们浏览网页的时候发生了什么吧。

1.首先我们在地址栏上输入我们想要打开的网址,然后我们通常会按下回车。这样一个请求就由浏览器以一种满足http协议的请求报文的形式发往服务器,请求报文中包含了要请求的页面地址,请求的文件类型等一系列信息。

2.在请求报文传递至客户端得网络设备的时候,网络设备把请求报文包装在一个满足TCP协议的数据中,通过网线传向服务器的网络设备。

3.服务器的网络设备接收到数据后,使用特殊的算法将数据解译,重新恢复成浏览器发出满足http协议的请求报文的形式,然后传向服务器软件。

4.服务软件得到请求报文后,根据请求报文所请求的页面地址在服务器的数据库中找到相应的页面,然后生成满足http协议的响应报文发向浏览器。响应报文中包括了响应报文头和被请求页面的代码(响应报文体)。

5.同样的,响应报文通过服务器的网络设备,被包装在一个满足TCP协议的数据,通过网线传向客户端的网络设备。

6.客户端的网络设备将响应报文解析,然后传给浏览器软件,浏览器在将响应报文解析,这样我们就在浏览器上看到了想要看到的网页。

以上只是浏览器与服务器之间通信的*简单的形式,实际使用中,一个网页往往包含着html代码,js代码,css样式表,图片等等多种数据,而这些数据并不是一次性由服务器传给浏览器的,而是存在着一定的顺序。首先服务器收到浏览器的请求后会将html代码发给浏览器,浏览器收到响应后会解析响应报文,发现html代码中包含着js代码和css样式表,而浏览器端并没有这些数据,所以浏览器会再次发送请求,向服务器请求js代码或css样式表数据(注意一次只能请求一种类型的数据),服务器收到请求后,会根据浏览器的请求再次找到数据库中的js文件或css样式表,将其发送到浏览器端。当网页中包含图片的时候也是同理。就这样循环往复,经过多次浏览器的请求和服务器的响应,当浏览器发现自己已经有了所有需要的数据后,会停止发送请求,这样一个完整的网页就呈现在我们眼前了。

以上只是浏览器与服务器之间通信的大致过程,要想详细了解其中门道还请各位参考更详细的文章。

服务器集群中服务器之间如何通信

在用Python做通信时,遇到服务器与服务器之间通信时,遇到如下问题
服务器集群中服务器之间如何通信?

网上看到好多人是通过以下方式去做的:

在做服务器集群时,集群中的服务器需要通信,比如Client1(简称C1)连接到Server1(简称S1),Client2连接到Server2,Client1需要向Client2发消息,S1并不知道C2已连接到S2。

A方案:采用组播(或广播),S1在接收到C1消息后,发送广播包查询C2位于哪个Server上,这时S2向S1回复,S1再将消息发送到S2,S2转发给C2,但是udp是不可靠的,虽然Server都位于同一局域网内,如果消息丢了,那C2就接收不到C1的消息了。

B方案:增加一个路由服务器,所有Server都连接到路由服务器(tcp长连接),S1将消息转发给路由服务器,路由服务器再广播给所有Server,由各个Server自行判断,但这样程序复杂度就上升了,每个Server都会处理本来不属于自己处理的消息,而且路由服务器会成为瓶颈,消息数量大规模增加的话。

这不就是个消息队列嘛,简单的可以用zeromq做,稍微复杂一点可以用rabbitmq/activemq/qpid等等各种成熟方案。

rabbitmq
MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM WEBSPHERE MQ等等。

ActiveMQ
1、ActiveMQ是消息队列技术,为解决高并发问题而生!

2、ActiveMQ生产者消费者模型(生产者和消费者可以跨平台、跨系统)

有中间平台

3、ActiveMQ支持两种消息传输方式

1)Queue,队列模式,生产者生产了一个消息,只能由一个消费者进行消费

2)Topic,发布/订阅模式,生产者生产了一个消息,可以由多个消费者进行消费

Qpid
AMQP是一种用于业务消息的开放网络协议。他定义了一种允许双方进行可靠业务消息传递的二进制线级协议。该协议的目标是成为所有消息中间件之间进行互操作的标准协议。

消息队列是一种进程间通信线程或同一进程的不同线程间的通信方式。

Qpid则是由Apache开发的一种消息队列,实现了AMQP协议,并且支持多种语言与多种平台。

zeromq
这是个类似于Socket的一系列接口,他跟Socket的区别是:普通的socket是端到端的(1:1的关系),而ZMQ却是可以N:M 的关系,人们对BSD套接字的了解较多的是点对点的连接,点对点连接需要显式地建立连接、销毁连接、选择协议(TCP/UDP)和处理错误等,而ZMQ屏蔽了这些细节,让你的网络编程更为简单。ZMQ用于node与node间的通信,node可以是主机或者是进程。

引用官方的说法: “ZMQ(以下ZeroMQ简称ZMQ)是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。ZMQ的明确目标是“成为标准网络协议栈的一部分,之后进入Linux内核”。现在还未看到它们的成功。但是,它无疑是*具前景的、并且是人们更加需要的“传统”BSD套接字之上的一 层封装。ZMQ让编写高性能网络应用程序*为简单和有趣。”

这不就是个消息队列嘛,简单的可以用zeromq做,稍微复杂一点可以用rabbitmq/activemq/qpid等等各种成熟方案

我看了下zeromq资料,它是用的tcp,通过一个路由服务器来转发(发布-订阅,请求-应答等等)。我的问题这种转发服务器会是一个瓶颈额,比如设计目标并发量10万,即每秒10万条消息,要求所有消息1秒内处理完,他能即时处理?

消息队列很成熟了,你要想性能好,就加机器来解决。

看消息大小,0mq官网有测试数据,8字节的消息每秒可以吞吐280万条(10G网络)或者400万条(infiniband),100字节的消息每秒都在100万条以上,每秒10万并不是一个特别巨大的量。想要性能可以堆机器,分布式消息队列很成熟了。

吞吐能力是接收和发送的总和?还是单单是接收?其实我想知道它的分发能力,比如说有10个服务器向它订阅了消息,那1秒它能同时分发给这10台服务器的消息量有多大?

官网有很具体的报告可以参考,建议自己搭环境实际测试,在普通PC和千兆网卡的环境里,是不可能有官方测出来的那个成绩的

我的程序中用的就是“广播”,主动或被动发送状态。

请问你是如何解决udp广播中丢消息的问题呢?

建立应答与重发机制

在分布式调度系统中,如果要实现调度服务器与多台计算节点服务器之间通信,采用socket来实现是一种实现方式,当然我们也可以通过数据存储任务,子节点来完成任务,但是往往使用数据作为任务存储都需要定制开发,要维护数据库中任务记录状态等等。开发的东西还是有点多,而且还不够灵活。因此,我个人是比较偏向于使用socket来实现任务的调度工作。原因:使用socket实现调度比较灵活,而且扩展性都比较好。

实现思路:调度服务器要实现调度工作,它必须与所有计算节点之间建立连接。而且他需要知道每台计算节点的任务状况,因此服务器节点必须存储与所有计算节点的socket连接对象。

在客户端唯一需要知道的就是它归属的调度服务器的通信IP和端口,因此client是发送连接的主动方,由调度服务器监听是否有client请求建立连接,当建立连接成功后,把该连接信息存储到一个结合中以便监控client的存货状态及通信使用。

扩展:

由于server端是存储了所有server与client的连接对象,因此我们是可以基于此demo的基础上实现聊天系统:

* 每当一个与用户发言时,是由server接收到的某个用户的发言信息的,此时服务器端可以通过循环发送该用户发送的信息给每个已经连接连接的用户(排除发送者)。

个人总结
可以见解负载均衡nginx的设计思想,进程间通信,队列,中间服务器,缓存等思想

浏览器与服务器交互的过程

浏览器与服务器交互的过程

4.1、浏览器与服务器交互图

当我们打开浏览器,在浏览器的地址栏中输入URL地址”http://www.gacl.cn:8080/JavaWebDemo1/1.jsp”去访问服务器上的1.jsp这个web资源的过程中,浏览器和服务器都做了神马操作呢,我们是怎么在浏览器里面看到1.jsp这个web资源里面的内容的呢?

浏览器和服务器做了以下几个操作:

1、浏览器根据主机名”www.gacl.cn”去操作系统的Hosts文件中查找主机名对应的IP地址。

2、浏览器如果在操作系统的Hosts文件中没有找到对应的IP地址,就去互联网上的DNS服务器上查找”www.gacl.cn”这台主机对应的IP地址。

3、浏览器查找到”www.gacl.cn”这台主机对应的IP地址后,就使用IP地址连接到Web服务器。

4、浏览器连接到web服务器后,就使用http协议向服务器发送请求,发送请求的过程中,浏览器会向Web服务器以Stream(流)的形式传输数据,告诉Web服务器要访问服务器里面的哪个Web应用下的Web资源,如下图所示:

%title插图%num

这就是浏览器向Web服务器发请求时向服务器传输的数据,解释一下”GET /JavaWebDemo1/1.jsp HTTP/1.1“这里面的内容,

GET:告诉Web服务器,浏览器是以GET的方式向服务器发请求。

/JavaWebDemo1/1.jsp:告诉Web服务器,浏览器要访问JavaWebDemo1应用里面的1.jsp这个Web资源。

    HTTP/1.1:告诉Web服务器,浏览器是以HTTP协议请求的,使用的是1.1的版本。

5、浏览器做完上面4步工作后,就开始等待,等待Web服务器把自己想要访问的1.jsp这个Web资源传输给它。

6、服务器接收到浏览器传输的数据后,开始解析接收到的数据,服务器解析”GET /JavaWebDemo1/1.jsp HTTP/1.1“里面的内容时知道客户端浏览器要访问的是JavaWebDemo1应用里面的1.jsp这个Web资源,然后服务器就去读取1.jsp这个Web资源里面的内容,将读到的内容再以Stream(流)的形式传输给浏览器,如下图所示:

%title插图%num

这个就是Web服务器传输给浏览器的数据。

7、浏览器拿到服务器传输给它的数据之后,就可以把数据展现给用户看了,如下图所示:

%title插图%num

看到的这个”JavaWebDemo1″就是浏览器解析服务器发送回来的数据后的效果

服务器发送回来的数据:

 1 HTTP/1.1 200 OK
 2 Server: Apache-Coyote/1.1
 3 Content-Type: text/html;charset=ISO-8859-1
 4 Content-Length: 102
 5 Date: Mon, 19 May 2014 14:25:14 GMT
 6 
 7 <html>
 8     <head>
 9         <title>JavaWebDemo1</title>
10     </head>
11     <body>
12         JavaWebDemo1
13 
14     </body>
15 </html>

这就是浏览器和服务器的交互过程。

云计算人员如何提高效率 要掌握哪些Linux命令

云计算人员如何提高效率?要掌握哪些Linux命令?随着开源软件的流行以及互联网的高速发展,Linux成功取代Unix成为*受青睐的云计算操作系统。想要学好云计算一定要掌握Linux,接下来就给大家分享云计算人员提高效率工作必须要掌握的Linux命令。

%title插图%num

查看命令

tail -f+文件名 实时显示日志文件内容。还可以使用less命令查看文件内容,并且使用shift+f键也可达到类似的效果。

查看磁盘或内存

Free -h 通过free的结果,很容易看到当前总共内存多少,剩余可用内存多少等。

进程操作

pgrep 进程名称 根据名称查找进程id

killall 进程名称 根据名称杀死进程

pkill 进程名称 根据名称杀死进程

ps -p 进程id -o lstart,etime 查看进程运行时间

快速目录切换

cd - 回到上一个目录

cd 回到用户家目录

清空文件内容

>filename

常用快捷命令

Ctrl+a 光标回到命令行首*

Ctrl+e 光标回到命令行尾*

Ctrl+f 光标向右移动一个字符(相当于方向键右键)

Ctrl+b 光标向左移动一个字符(相当于方向键左键)

Ctrl+Insert 复制命令行内容*

Shift+Insert 粘贴命令行内容*

Ctrl+k 剪切(删除)光标处到行尾的字符*

Ctrl+u 剪切(删除)光标处到行首的字符*

Ctrl+w 剪切(删除)光标前的一个单词

Ctrl+y 粘贴Ctrl+u,Ctrl+k,Ctrl+w删除的文本

Ctrl+c 中断终端正在执行的任务或者删除整行*

Ctrl+h 删除光标所在处的前一个字符(相当于退格键)

Ctrl+d 退出当前Shell命令行*

Ctrl+r 搜索命令行使用过的历史命令记录*

Ctrl+g 从执行Ctrl+r的搜索历史命令模式退出

Esc+.(点) 获取上一条命令的*后的部分(空格分隔)*

Ctrl+l 清除屏幕所有内容,并在屏幕*上面开始一个新行,等同clear命令*

Ctrl+s 锁定终端,使之无法输入内容

Ctrl+q 解锁执行Ctrl+s的锁定状态

Ctrl+z 暂停执行在终端运行的任务*

!! 执行上一条命令

!pw 执行*近以pw开头的命令*

!pw:p 仅打印*近pw开头的命令,但不执行

!num 执行历史命令列表的第num(数字)条命令*

!$ 上一条命令的*后一个参数,相当于Esc+.(点)

Esc+.(点) 获取上一条命令的*后的部分(空格分隔)*

Esc+b 移动到当前单词的开头

Esc+f 移动到当前单词的结尾

Esc+t 颠倒光标所在处及其相邻单词的位置

当然,牢记Linux命令并不代表你就是一个合格的云计算人才,你还需要熟练应用Linux命令,需要掌握云计算相关技能,了解docker容器技术等。如果你想快速掌握这一系列的技术,专业的学习让你高效、快速掌握企业所需的高薪技术!

利用idrac安装操作系统(dell r730)

题外话:每日七点,QQ群大家分享技术相关文章,睡什么睡起来嗨!

QQ群号:630300475

正文:(1)准备好iso镜像

            (2)进入idrac,进入虚拟终端

    (3)点击虚拟终端上部的虚拟介质

%title插图%num

   (4)单击  连接介质 —-> 映射cd/DVD

%title插图%num

(5)选择你的镜像的位置

%title插图%num

%title插图%num

(6)选择虚拟终端上面的 下次引导 —->  虚拟cd/Dvd

(7)重启机器,后面就和安装虚拟机一样了

戴尔 iDRAC 命令行工具及常用命令

标签:iDRAC 远程命令工具   戴尔iDRAC远程命令工具   OM LRAU   iDRAC创建用户   iDRAC的IP修改

1、RHEL 系统环境iDRAC 命令工具包:

Dell EMC OpenManage Linux Remote Access Utilities :http://www.dell.com/support/home/cn/zh/cndhs1/drivers/driversdetails?driverId=49T1M
下载后,需解决net-snmp-utils包的依赖关系在执行此目录下的rpm包安装/root/linux/rac/RHEL7/x86_64,然后软链接
物理机环境的安装和虚拟机环境安装区别:
物理机环境:安装在物理机环境后,可直接 # racadm command查看和修改iDRAC配置
虚拟机环境:安装在虚拟机环境后,需 -r IP #racadm -r 192.168.1.1 -u User -p ‘Password‘ command 查看和修改iDRAC配置
2、iDRAC 命令手册:

http://topics-cdn.dell.com/pdf/idrac7-8-lifecycle-controller-v2.50.50.50_reference-guide_en-us.pdf
3、iDRAC 常用命令

创建、删除、赋权用户的操作
# racadm config -g cfgUserAdmin -o cfgUserAdminUserName -i 10 User01 创建索引10的用户User01
# racadm config -g cfgUserAdmin -o cfgUserAdminPassword -i 10 ‘Password‘ 给创建的用户设置密码
# racadm set iDRAC.Users.10.Password ‘NewPassword‘ 更改用户密码
# racadm config -g cfgUserAdmin -i 10 -o cfgUserAdminEnable 1 启用用户<1表示启用,0表示禁用>
# racadm config -g cfgUserAdmin -o cfgUserAdminUserName -i 10 删除用户
# racadm config -g cfgUserAdmin -o cfgUserAdminPrivilege -i 10 4 赋予User01用户超级管理员权限
物理机重启、关机等操作
# racadm serveraction powerup 开启服务器
# racadm serveraction powerdown 关闭服务器
# racadm serveraction powercycle 关机后再开启服务器
# racadm serveraction powerstatus 查看服务器状态
iDRAC 重启操作
# racadm racreset soft 软重启iDRAC
# racadm racreset hard 硬重启iDRAC
# racadm racreset soft -f 强制软重启iDRAC
# racadm racreset hard -f 强制硬重启iDRAC
# racadm set iDRAC.IPv4.Address x.x.x.x 修改IP地址
# racadm set iDRAC.IPv4.Netmask x.x.x.x 修改子网掩码
# racadm set iDRAC.IPv4.Gateway x.x.x.x 修改默认网关<无需重启idrac,配置即生效>

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速