学习https://github.com/huoyu820125/SecondPaxos 自己编写网络版本

在学习过程将此代码的线程 锁等改成c++11  就不用包含那么多文件

主要更改如下

 // MyPaxos.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream>
#include <chrono>
#include <mutex>
#include <thread>
#include "Acceptor.h"
#include "Proposer.h" paxos::Proposer p[];
paxos::Acceptor a[];
int finishedCount = ;
std::mutex l[]; std::mutex printlock; void Proposer(int id) {
paxos::Proposer &proposer = p[(int)id];
paxos::PROPOSAL value = proposer.GetProposal();
paxos::PROPOSAL lastValue; int acceptorId[];
int count = ; while (true) {
value = proposer.GetProposal();//拿到提议
printlock.lock();
std::cout << "Proposer" << (int)id << "号开始(Propose阶段):提议=[编号:" << value.serialNum
<< ",提议:" << value.value << "]\n";
printlock.unlock();
count = ;
int i = ; for (i = ; i < ; i++)
{
/*
* 发送消息到第i个acceptor
* 经过一定时间达到acceptor,sleep(随机时间)模拟
* acceptor处理消息,mAcceptors[i].Propose()
* 回应proposer
* 经过一定时间proposer收到回应,sleep(随机时间)模拟
* proposer处理回应mProposer.proposed(ok, lastValue)
*/
//经过随机时间,消息到达了mAcceptors[i]
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % ) );
l[i].lock();
bool ok = a[i].Propose(value.serialNum, lastValue);
l[i].unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % ));
//处理Propose回应
if (!proposer.Proposed(ok, lastValue)) //重新开始Propose阶段
{
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % ));
//为了降低活锁,多等一会让别的proposer有机会完成自己的2阶段批准
break;
}
paxos::PROPOSAL curValue = proposer.GetProposal();//拿到提议
if (curValue.value != value.value)//acceptor本次回应可能推荐了一个提议
{
printlock.lock();
std::cout << "Proposer" << (int)id << "号修改了提议:提议=[编号:" <<
curValue.serialNum << ",提议:" << curValue.value << "]\n";
printlock.unlock();
}
acceptorId[count++] = i;//记录愿意投票的acceptor
if (proposer.StartAccept())
{
if ( == rand() % ) break;
}
}
//检查有没有达到Accept开始条件,如果没有表示要重新开始Propose阶段
if (!proposer.StartAccept()) continue;
//开始Accept阶段
//发送Accept消息到所有愿意投票的acceptor
value = proposer.GetProposal();
printlock.lock();
std::cout << "Proposer" << (int)id << "号开始(Accept阶段):提议=[编号:" <<
value.serialNum << ",提议:" << value.value << "]\n";
printlock.unlock();
for (i = ; i < count; i++)
{
//发送accept消息到acceptor
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % ));//经过随机时间,accept消息到达acceptor
//处理accept消息
l[acceptorId[i]].lock();
bool ok = a[acceptorId[i]].Accept(value);
l[acceptorId[i]].unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % ));//经过随机时间,accept回应到达proposer
//处理accept回应
if (!proposer.Accepted(ok)) //重新开始Propose阶段
{
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % ));///为了降低活锁,多等一会让别的proposer有机会完成自己的2阶段批准
break;
}
if (proposer.IsAgree())//成功批准了提议
{
printlock.lock();
std::cout << "Proposer" << (int)id << "号批准了提议:最终提议 = [编号:" <<
value.serialNum << ",提议:" << value.value << "]\n";
printlock.unlock();
return ;
}
}
}
return ;
} int main()
{
int i = ;
std::cout << "11个Proposer, 11个Acceptor准备进行Paxos\n"<<
"每个Proposer独立线程,Acceptor不需要线程\n"<<
"Proposer线程中等待随机时间:表示与Acceptor的通信时间\n"<<
"Proposer线程中调用Acceptor.Proposed()表示拿到了Propose请求结果\n"<<
"Proposer线程中调用Acceptor.Accepted()表示拿到了Accept请求结果\n"<<
"Proposer被批准后结束线程,其它线程继续投票最终,全部批准相同的值,达成一致。\n"; paxos::PROPOSAL value;
for (i = ; i < ; i++)
{
p[i].SetPlayerCount(, );
value.serialNum = value.value = i + ;
p[i].StartPropose(value);
} std::thread t[];
for (i = ; i < ; i++) {
t[i] = std::thread(Proposer, i);
}
for (i = ; i < ; i++) {
t[i].join();
}
while (true) {
std::this_thread::sleep_for(std::chrono::seconds());
} return ;
}

20180513添加

根据视频  paxos和分布式系统_1024x768_2.00M_h.264

添加自写代码 vs2017 boost1.65编译

方案1  单点接收多点提交 二段提交 抢占提交权

// Accepter.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp> using boost::asio::ip::tcp; const int default_port = ; #pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{
int index; //当前请求的阶段
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}PROPOSAL; typedef struct ACCEPTSAL
{
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}ACCEPTSAL;
#pragma pack() enum INDEX {
INIT_INDEX = ,
PREPARE_INDEX,
ACCEPT_INDEX,
FINISH_INDEX,
ERROR_INDEX = -,
}; int current_index = PREPARE_INDEX;
ACCEPTSAL g_ServerRecord = {-,- };
boost::asio::io_service io_service;
std::mutex g_mtx;
int acceptepoch = -;
//========================================================== void HandlePropose(std::shared_ptr<tcp::socket> socket) {
PROPOSAL buf = { -,-,- };
ACCEPTSAL tmpAcpsal = { -,- }; try {
while () {
boost::asio::read(*socket, boost::asio::buffer(&buf, sizeof(buf)));
{
std::lock_guard<std::mutex> lock(g_mtx);
//prepare阶段
if (buf.index == PREPARE_INDEX) {
if (g_ServerRecord.epoch <= buf.epoch && g_ServerRecord.value == -) {
//更新最新的prepare epoch
g_ServerRecord.epoch = buf.epoch;
current_index = ACCEPT_INDEX;
}
}
else if (buf.index == ACCEPT_INDEX && (- == g_ServerRecord.value)) {
if ((buf.epoch >= g_ServerRecord.epoch)) {
g_ServerRecord.value = buf.value;
current_index = FINISH_INDEX;
}
}
//拷贝accepter记录
tmpAcpsal = g_ServerRecord;
}
//回复
boost::asio::write(*socket, boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)));
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
return;
}
} int main()
{
try {
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), default_port));
for (;;) {
std::shared_ptr<tcp::socket> psocket = std::make_shared<tcp::socket>(io_service);
acceptor.accept(*psocket); std::thread t(HandlePropose,psocket);
t.detach();
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
} return ;
}

accepter

// Proposer.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp> using boost::asio::ip::tcp; const std::string default_port = ""; #pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{
int index; //当前请求的阶段
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}PROPOSAL; typedef struct ACCEPTSAL
{
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}ACCEPTSAL;
#pragma pack() enum INDEX {
INIT_INDEX = ,
PREPARE_INDEX,
ACCEPT_INDEX,
FINISH_INDEX,
ERROR_INDEX = -,
}; //======================================================== int main()
{
try {
boost::asio::io_service io_service; tcp::resolver resolver(io_service);
tcp::resolver::query query("127.0.0.1", default_port.c_str());
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator); for (;;) {
PROPOSAL pro = { PREPARE_INDEX ,, };
ACCEPTSAL tmpAcpsal = { -,- };
boost::system::error_code error; boost::asio::write(socket, boost::asio::buffer(&pro,sizeof(pro)), error); size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal,sizeof(tmpAcpsal)), error); if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
if (tmpAcpsal.epoch == pro.epoch) {
pro.index = ACCEPT_INDEX;
boost::asio::write(socket, boost::asio::buffer(&pro, sizeof(pro)), error);
size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)), error);
}
if (tmpAcpsal.value != -) {
std::cout << " value is " << tmpAcpsal.value << std::endl;
system("pause");
return ;
}
else {
std::cerr << " value is " << tmpAcpsal.value << " . Error !!!" << std::endl;
system("pause");
return ;
} }
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
} system("pause"); return ;
}

propose

缺点 若抢占的propose 出现故障 则无法释放锁

方案2 单点接受多点提交 二段提交 根据epoch抢占提交权 若获取提交权的proposer出现故障 将会被拥有更高epoch的propose替代

// Accepter.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp> using boost::asio::ip::tcp; const int default_port = ; #pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{
int index; //当前请求的阶段
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}PROPOSAL; typedef struct ACCEPTSAL
{
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}ACCEPTSAL;
#pragma pack() enum INDEX {
INIT_INDEX = ,
PREPARE_INDEX,
ACCEPT_INDEX,
FINISH_INDEX,
ERROR_INDEX = -,
}; int current_index = PREPARE_INDEX;
ACCEPTSAL g_ServerRecord = {-,- };
boost::asio::io_service io_service;
std::mutex g_mtx;
int acceptepoch = -;
//========================================================== void HandlePropose(std::shared_ptr<tcp::socket> socket) {
PROPOSAL buf = { -,-,- };
ACCEPTSAL tmpAcpsal = { -,- }; try {
while () {
boost::asio::read(*socket, boost::asio::buffer(&buf, sizeof(buf)));
{
std::lock_guard<std::mutex> lock(g_mtx);
std::cout << "recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;
} {
std::lock_guard<std::mutex> lock(g_mtx);
//prepare阶段
if (buf.index == PREPARE_INDEX) {
if (g_ServerRecord.epoch <= buf.epoch && g_ServerRecord.value == -) {
std::cout << "Prepare index" << std::endl;
std::cout << "Prepare recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;
//更新最新的prepare epoch
g_ServerRecord.epoch = buf.epoch;
current_index = ACCEPT_INDEX;
}
}
else if (buf.index == ACCEPT_INDEX && (- == g_ServerRecord.value)) {
if ((buf.epoch >= g_ServerRecord.epoch)) {
std::cout << "Accept index, epoch =" << buf.epoch << ".value = "<< buf.value << std::endl;
g_ServerRecord.epoch = buf.epoch;
g_ServerRecord.value = buf.value;
current_index = FINISH_INDEX;
}
}
//拷贝accepter记录
tmpAcpsal = g_ServerRecord;
}
//回复
{
std::lock_guard<std::mutex> lock(g_mtx);
std::cout << "reply epoch = " << tmpAcpsal.epoch << ". value = " << tmpAcpsal.value << std::endl;
}
boost::asio::write(*socket, boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)));
}
}
catch (std::exception& e) {
//std::cerr << e.what() << std::endl;
return;
}
} int main()
{
try {
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), default_port));
for (;;) {
std::shared_ptr<tcp::socket> psocket = std::make_shared<tcp::socket>(io_service);
acceptor.accept(*psocket); std::thread t(HandlePropose,psocket);
t.detach();
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
} return ;
}

accepter

// Proposer.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <random>
#include <thread>
#include <boost/asio.hpp> using boost::asio::ip::tcp; const std::string default_port = ""; #pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{
int index; //当前请求的阶段
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}PROPOSAL; typedef struct ACCEPTSAL
{
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}ACCEPTSAL;
#pragma pack() enum INDEX {
INIT_INDEX = ,
PREPARE_INDEX,
ACCEPT_INDEX,
FINISH_INDEX,
ERROR_INDEX = -,
};
//========================================================
boost::asio::io_service io_service; unsigned GetRand()
{
static std::default_random_engine e;
static std::uniform_int_distribution<unsigned> u(, );
return u(e);
} void ProposeThreadFunc(int id) {
try {
tcp::resolver resolver(io_service);
tcp::resolver::query query("127.0.0.1", default_port.c_str());
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
int epoch = id+;
for (;;) {
PROPOSAL pro = { PREPARE_INDEX ,epoch +,id + };
ACCEPTSAL tmpAcpsal = { -,- };
boost::system::error_code error; boost::asio::write(socket, boost::asio::buffer(&pro, sizeof(pro)), error); size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)), error); if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
if (tmpAcpsal.epoch == pro.epoch) {
pro.index = ACCEPT_INDEX; std::chrono::milliseconds dura(GetRand());
std::this_thread::sleep_for(dura); boost::asio::write(socket, boost::asio::buffer(&pro, sizeof(pro)), error);
size_t len = socket.read_some(boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)), error);
}
if (tmpAcpsal.epoch > epoch) {
int i = tmpAcpsal.epoch%;
int loopcount = tmpAcpsal.epoch / ;
epoch = loopcount * + + id + ;
if(id == )
std::cout << "epoch = " << epoch << std::endl;
}
if (tmpAcpsal.value != -) {
std::cout << " value is " << tmpAcpsal.value << std::endl;
break ;
}
std::chrono::milliseconds dura(GetRand());
std::this_thread::sleep_for(dura);
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
} int main()
{
std::thread t[];
for (int i = ; i < ; i++) {
t[i] = std::thread(ProposeThreadFunc,i);
}
for (int i = ; i < ; i++) {
t[i].join();
} system("pause");
return ;
}

propose

运行代码 添加随机参数 最后提交接受的数值 实现随机化

运行第一次 最后接受数值为6

运行第二次 最后接受数值为2

accept扩展多点 匹配客户端待完成

// accepters.cpp: 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <ctime>
#include <iostream>
#include <string>
#include <memory>
#include <mutex>
#include <thread>
#include <boost/asio.hpp> using boost::asio::ip::tcp; const int default_port = ; #pragma pack (1)
//提议数据结构
typedef struct PROPOSAL
{
int index; //当前请求的阶段
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}PROPOSAL; typedef struct ACCEPTSAL
{
int epoch; //流水号,1开始递增,保证全局唯一
int value; //提议内容
}ACCEPTSAL;
#pragma pack() enum INDEX {
INIT_INDEX = ,
PREPARE_INDEX,
ACCEPT_INDEX,
FINISH_INDEX,
ERROR_INDEX = -,
};
//=======================================================
//多个accepter记录
boost::asio::io_service io_service; int current_index[];// = PREPARE_INDEX;
ACCEPTSAL g_ServerRecord[];// = { -1,-1 };
std::mutex g_mtx[];
std::mutex g_print_mtx;
int acceptepoch[];// = -1; //=====================================================
void HandlePropose(std::shared_ptr<tcp::socket> socket,int id) {
PROPOSAL buf = { -,-,- };
ACCEPTSAL tmpAcpsal = { -,- }; try {
while () {
boost::asio::read(*socket, boost::asio::buffer(&buf, sizeof(buf)));
{
std::lock_guard<std::mutex> lock(g_mtx[id]);
std::lock_guard<std::mutex> printLock(g_print_mtx);
std::cout << "recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;
} {
std::lock_guard<std::mutex> lock(g_mtx[id]);
//prepare阶段
if (buf.index == PREPARE_INDEX) {
if (g_ServerRecord[id].epoch <= buf.epoch && g_ServerRecord[id].value == -) {
{
std::lock_guard<std::mutex> printLock(g_print_mtx);
std::cout << "Prepare index" << std::endl;
std::cout << "Prepare recv " << "index = " << buf.index << ". epoch = " << buf.epoch << ". value = " << buf.value << std::endl;
}
//更新最新的prepare epoch
g_ServerRecord[id].epoch = buf.epoch;
current_index[id] = ACCEPT_INDEX;
}
}
else if (buf.index == ACCEPT_INDEX && (- == g_ServerRecord[id].value)) {
if ((buf.epoch >= g_ServerRecord[id].epoch)) {
{
std::lock_guard<std::mutex> printLock(g_print_mtx);
std::cout << "Accept index, epoch =" << buf.epoch << ".value = " << buf.value << std::endl;
}
g_ServerRecord[id].epoch = buf.epoch;
g_ServerRecord[id].value = buf.value;
current_index[id] = FINISH_INDEX;
}
}
//拷贝accepter记录
tmpAcpsal = g_ServerRecord[id];
}
//回复
{
std::lock_guard<std::mutex> lock(g_mtx[id]);
{
std::lock_guard<std::mutex> printLock(g_print_mtx);
std::cout << "reply epoch = " << tmpAcpsal.epoch << ". value = " << tmpAcpsal.value << std::endl;
}
}
boost::asio::write(*socket, boost::asio::buffer(&tmpAcpsal, sizeof(tmpAcpsal)));
}
}
catch (std::exception& e) {
//std::cerr << e.what() << std::endl;
return;
}
} void AcceptThreadFunc(int id) {
try {
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), default_port+id));
for (;;) {
std::shared_ptr<tcp::socket> psocket = std::make_shared<tcp::socket>(io_service);
acceptor.accept(*psocket); std::thread t(HandlePropose, psocket,id);
t.detach();
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
} void init() {
for (int i = ; i < ; i++) {
current_index[i] = PREPARE_INDEX;
g_ServerRecord[i].epoch = -;
g_ServerRecord[i].value = -;
}
} int main()
{
init();
std::thread t[];
for (int i = ; i < ; i++) {
t[i] = std::thread(AcceptThreadFunc,i);
}
for (int i = ; i < ; i++) {
t[i].join();
} return ;
}

paxos 练手 推进中的更多相关文章

  1. 简单的node爬虫练手,循环中的异步转同步

    简单的node爬虫练手,循环中的异步转同步 转载:https://blog.csdn.net/qq_24504525/article/details/77856989 看到网上一些基于node做的爬虫 ...

  2. 推荐:一个适合于Python新手的入门练手项目

    随着人工智能的兴起,国内掀起了一股Python学习热潮,入门级编程语言,大多选择Python,有经验的程序员,也开始学习Python,正所谓是人生苦短,我用Python 有个Python入门练手项目, ...

  3. web前端学习部落22群分享给需要前端练手项目

    前端学习还是很有趣的,可以较快的上手然后自己开发一些好玩的项目来练手,网上也可以一抓一大把关于前端开发的小项目,可是还是有新手在学习的时候不知道可以做什么,以及怎么做,因此,就整理了一些前端项目教程, ...

  4. webpack练手项目之easySlide(三):commonChunks(转)

    Hello,大家好. 在之前两篇文章中: webpack练手项目之easySlide(一):初探webpack webpack练手项目之easySlide(二):代码分割 与大家分享了webpack的 ...

  5. webpack练手项目之easySlide(二):代码分割(转)

    在上一篇 webpack练手项目之easySlide(一):初探webpack  中我们一起为大家介绍了webpack的基本用法,使用webpack对前端代码进行模块化打包. 但是乍一看webpack ...

  6. webpack练手项目之easySlide(一):初探webpack (转)

    最近在学习webpack,正好拿了之前做的一个小组件,图片轮播来做了下练手,让我们一起来初步感受下webpack的神奇魅力.     webpack是一个前端的打包管理工具,大家可以前往:http:/ ...

  7. Python之路【第二十四篇】:Python学习路径及练手项目合集

      Python学习路径及练手项目合集 Wayne Shi· 2 个月前 参照:https://zhuanlan.zhihu.com/p/23561159 更多文章欢迎关注专栏:学习编程. 本系列Py ...

  8. 【开源】前端练手笔记,Chrome扩展应用程序(html+CSS+JS) (1)

    项目名称:github-notification 项目地址:https://github.com/WQTeam/github-notification 说明:本人打算抽时间学习前端(html + cs ...

  9. 仿PC版微信的练手项目(可实时通讯)

    仿PC版微信的DEMO 本项目是由一个仿PC版微信的vue前端项目,和一个使用leancloud进行数据存储的.提供WebSocket的node后端项目构成. 本项目使用的技术栈:vue + vue- ...

随机推荐

  1. git查看某个文件修改历史

    [git查看某个文件修改历史] 1.使用git命令 git whatchanged charge.lua 显示某个文件的每个版本提交信息:提交日期,提交人员,版本号,提交备注(没有修改细节) git ...

  2. 使用Jmeter(三十)针对ActiveMQ JMS POINT TO POINT压力测试(转载)

    转载自 http://www.cnblogs.com/yangxia-test 准备工作 针对JMS类型的Sampler,需要额外的jar包(这里用的是apache ActiveMQ,将下载的AMQ  ...

  3. day30 UDP协议

    本周安排 周二 socket编程 周三 粘包处理 周四 选课系统 并发编程 周五多道技术 多进程 周六 IPC 互斥锁 常用模块 os* 操作系统 多数是文件操作 os.path 处理文件路径 shu ...

  4. 【scrapy_redis】调试后爬取了部分数据,然后重新调试时,直接被去重机制过滤掉无法重头开始爬取

    这2天遇到一个问题,之前调试的时候爬取了一些数据,结果第二天重新调试的时候发现爬虫很快结束,而且还没有报错.后来从日志里看到这个: no more duplicates will be shown ( ...

  5. C# winform 支持html5的 控件

    OpenWebKitSharp WebKit.net c#winform中使用WebKit传递js对象实现与网页交互 分类: .NET开发2013-08-18 23:55 2496人阅读 评论(1)  ...

  6. 数值的整数次方(python)

    题目描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. # -*- coding:utf-8 -*- class Solution: ...

  7. Mybatis抛出 Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@f54509]异常

    今天在做Springmvc和spring 时 mybatis 是抛出异常 Closing non transactional SqlSession [org.apache.ibatis.session ...

  8. tcp/ip通信第5期之服务器端程序

    /* 此程序是tcp/ip通信服务器端程序,测试运行在redhat5上 重构readline函数,解决粘包问题——利用“\n”识别一个消息边界 */ #include<stdio.h> # ...

  9. ABAP中不修改内表参照的结构,给内表/结构体增加字段

    Situation: DATA:       itab  TYPE STANDARD TABLE OF zsrsodtla_stru1,      wa_itab TYPE zsrsodtla_str ...

  10. Bootstrap(6)辅组类和响应式工具

    一.辅助类 Bootstrap 在布局方面提供了一些细小的辅组样式,用于文字颜色以及背景色的设置.显示关闭图标等等. 1.情景文本颜色 各种色调的字体 <p class="text-m ...