分类归档 C++

通过admin

利用XMPP实现文件共享—简析 “XMPP文件传输协议”

最近在研究XMPP协议,client端用的是开源的Gloox库,server使用gtalk server和OpenFire。昨天想实现XMPP的文件传输,于是仔细看了下XMPP的文件传输协议,结合协议和代码,算是把标准XMPP文件传输协议摸清楚了。下面是一些要点总结。

  • Sock5 Bytestreams支持点对点传输和通过Proxy中转。
  • 标准XMPP,使用Disco来发现代理服务器,所以即使发送方没有配置proxy server也没有问题(理论上哈)。不错的机制啊。
  • 点对点传输只支持Target去连接Requester,不支持双向,所以不是完全的P2P,Jingle file transfer对这一个应该做了优化。
  • Gtalk由于采用了Jingle  file transfer协议,所以没有提供用于文件传输的Proxy server,经过本人测试,下面提供解决方法:

1、发送文件的时候把自己启动一个sock5 server,以这个作为stream host。这种方式要求接受方必须是能够直连发送方,否则会出现失败。

2、指定第三方的Proxy server来实现文件传输,目前很多第三方proxy server貌似都会对ID做验证,所以最好是自己架设一个Sock5 Proxy server,实现起来应该不难。如果采用这中方式,建议不必要完全遵守XEP0065,可以对建立连接过程优化下,实现更彻底的“P2P”。(推荐)

3、使用In band bytestrreams方式。(不考虑性能的话,实现起来最简单)

4、在client端兼容Jingle协议。

1,2,3种方式只能实现第三方Client之间的文件传输,无法和官方Gtalk进行文件传输。

  • 我用的是开源的gloox库,gloox库没有支持Proxy代理服务发现机制,所以发文件放必须至少添加一个Stremhost,一般来说发文件放把自己建立一个Sock5server,并把自己和代理服务器添加到Streamhost中,主要代码:
1 m_pFt =new SIProfileFT(m_pClient,this);
2
3 m_pSock5Server =new SOCKS5BytestreamServer( m_pClient->logInstance(), 6666 );
4  if( (m_pSock5Server->listen() ) != ConnNoError )
5 {
6 g_bLisened = TRUE;
7 }
8 m_pFt->registerSOCKS5BytestreamServer(m_pSock5Server);
9 m_pFt->addStreamHost(m_pClient->jid(), “127.0.0.1”, 6666 );
10 m_pFt->addStreamHost(JID(c_szProxyServer), c_szProxyServer, 7777);

相关协议:

XEP-0096: SI File Transfer

源文档 <http://xmpp.org/extensions/xep-0096.html>

 

XEP-0065: SOCKS5 Bytestreams

源文档 <http://xmpp.org/extensions/xep-0065.html>

 

XEP-0234: Jingle File Transfer(还没研究过,不过应该差不多)

源文档 <http://xmpp.org/extensions/xep-0234.html>

通过admin

【原】自己动手实现动态外网ip管理和动态DNS域名解析

项目背景:

在自己的电脑装了linux 虚拟机,想要在外网也能ssh到虚拟机进行开发,由于路由ip是动态ip,想到网上找一些动态dns域名解析,但是效果不大好,所以想到自己进行外网ip的管理。

 

想法:

用C++写一个界面客户端,随系统启动,定时访问自己的cgi,更新自己的外网ip;这个客户端能支持简单的几个操作:启动,退出,设置更新间隔,是否随系统启动等。

写一个cgi,接收client请求,并记录最新的外网ip到数据库;

写另外一个cgi,在其他地方访问能列出当前最新的外网ip,以及历史ip列表。

可以再写一个跳转cgi:jump.php,访问这个cgi能够自动跳转到最新的外网ip对应的目录。

 

至此,一个简单的动态ip管理和dns解析功能就完成了。

 

编程环境选择:

Client:C++,MFC;

Server:Php+Mysql,服务器使用sina云平台。

 

项目进度:

编写CGI,updateip.php?m=update&uid=实现更新外网ip到数据库。

Php中获取ip的方式:

$ip=@$REMOTE_ADDR;

echo “<b>IP Address= $ip</b>”;

$ip=$_SERVER[‘REMOTE_ADDR’];

数据库设计:

Iplist:

建表:

Create table iplist(id int not null auto_increment,

Primary key(id),

uid VARCHAR(32),

ip VARCHAR(32),

updatetime datetime

)

 

<html>

<body>

 

CGi代码:

Update.php

<?php

$method = $_GET[‘m’];

if($method == “update”){

$ip=$_SERVER[‘REMOTE_ADDR’];

$uid = $_GET[‘uid’];

echo ‘Got it:uid=’.$uid.’,ip=’.$ip.'</BR>’;

 

//mysql_connect($_SAE_MYSQL_HOST_M,$_SAE_MYSQL_USER, $_SAE_MYSQL_PASS) or die(mysql_error());

//mysql_select_db($_SAE_MYSQL_DB) or die(mysql_error());

 

// Create a MySQL table in the selected database

 

$mysql = new SaeMysql();

 

$sql = “INSERT INTO `iplist` (`id`, `uid`, `ip`, `updatetime`) VALUES (NULL, ‘”.$uid.”‘, ‘”.$ip.”‘, now());”;

$mysql->runSql( $sql );

if( $mysql->errno() != 0 )

{

die( “Error:” . $mysql->errmsg() );

}

 

$mysql->closeDb();

 

 

}else{

$mysql = new SaeMysql();

$sql = “SELECT *

FROM `iplist`

ORDER BY `updatetime` DESC”;

 

$data = $mysql->getData( $sql );

foreach($data as $i => $value){

echo “Record:id=”.$value[‘id’].”,uid=”.$value[‘uid’].”,ip”.$value[‘ip’].”,updatetime”.$value[‘updatetime’].”</BR></BR>”;

}

 

if( $mysql->errno() != 0 )

{

die( “Error:” . $mysql->errmsg() );

}

 

$mysql->closeDb();

 

 

}

 

 

?>

 

</body>

</html>

 

用MFC编写一个简单的客户端,开机自动启动,定时请求服务器更新外网ip

 

client端主要代码,基于VS2005,MFC:

UpdateIp.rc
// Microsoft Visual C++ generated resource script.

//

#include “resource.h”

 

#define APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////

//

// Generated from the TEXTINCLUDE 2 resource.

//

#include “afxres.h”

 

/////////////////////////////////////////////////////////////////////////////

#undef APSTUDIO_READONLY_SYMBOLS

 

/////////////////////////////////////////////////////////////////////////////

// Chinese (P.R.C.) resources

 

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)

#ifdef _WIN32

LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#pragma code_page(936)

#endif //_WIN32

 

#ifdef APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////

//

// TEXTINCLUDE

//

 

1 TEXTINCLUDE

BEGIN

“resource.h\0”

END

 

2 TEXTINCLUDE

BEGIN

“#include “”afxres.h””\r\n”

“\0”

END

 

3 TEXTINCLUDE

BEGIN

“#define _AFX_NO_SPLITTER_RESOURCES\r\n”

“#define _AFX_NO_OLE_RESOURCES\r\n”

“#define _AFX_NO_TRACKER_RESOURCES\r\n”

“#define _AFX_NO_PROPERTY_RESOURCES\r\n”

“\r\n”

“#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)\r\n”

“LANGUAGE 4, 2\r\n”

“#pragma code_page(936)\r\n”

“#include “”res\\UpdateIp.rc2″”  // non-Microsoft Visual C++ edited resources\r\n”

“#include “”afxres.rc””     // Standard components\r\n”

“#endif\r\n”

“\0”

END

 

#endif    // APSTUDIO_INVOKED

 

 

/////////////////////////////////////////////////////////////////////////////

//

// Icon

//

 

// Icon with lowest ID value placed first to ensure application icon

// remains consistent on all systems.

IDR_MAINFRAME           ICON                    “res\\UpdateIp.ico”

 

/////////////////////////////////////////////////////////////////////////////

//

// Dialog

//

 

IDD_ABOUTBOX DIALOGEX 0, 0, 235, 55

STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU

CAPTION “About UpdateIp”

FONT 8, “MS Shell Dlg”, 0, 0, 0x1

BEGIN

ICON            IDR_MAINFRAME,IDC_STATIC,11,17,20,20

LTEXT           “UpdateIp Version 1.0”,IDC_STATIC,40,10,119,8,SS_NOPREFIX

LTEXT           “Copyright (C) 2012”,IDC_STATIC,40,25,119,8

DEFPUSHBUTTON   “OK”,IDOK,178,7,50,16,WS_GROUP

END

 

IDD_UPDATEIP_DIALOG DIALOGEX 0, 0, 144, 222

STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU

EXSTYLE WS_EX_APPWINDOW

CAPTION “UpdateIp”

FONT 8, “MS Shell Dlg”, 0, 0, 0x1

BEGIN

PUSHBUTTON      “停止服务”,IDC_BTN_STOPSERVICE,81,89,50,14

PUSHBUTTON      “启动服务”,IDC_BTN_STARTSERVICE,17,89,50,14

CONTROL         “随系统启动”,IDC_CHECK_AUTOSTART,”Button”,BS_AUTOCHECKBOX | WS_TABSTOP,19,25,56,10

EDITTEXT        IDC_EDIT_UPDATEINTERVAL,82,46,40,14,ES_AUTOHSCROLL | ES_NUMBER

LTEXT           “更新间隔(秒):”,IDC_STATIC,18,49,60,8

GROUPBOX        “设置”,IDC_STATIC,0,5,135,212

PUSHBUTTON      “保存”,IDC_SAVE,17,63,50,14

EDITTEXT        IDC_EDIT_RESULT,12,119,119,88,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_VSCROLL,WS_EX_STATICEDGE

END

 

 

/////////////////////////////////////////////////////////////////////////////

//

// Version

//

 

VS_VERSION_INFO VERSIONINFO

FILEVERSION 1,0,0,1

PRODUCTVERSION 1,0,0,1

FILEFLAGSMASK 0x3fL

#ifdef _DEBUG

FILEFLAGS 0x1L

#else

FILEFLAGS 0x0L

#endif

FILEOS 0x4L

FILETYPE 0x1L

FILESUBTYPE 0x0L

BEGIN

BLOCK “StringFileInfo”

BEGIN

BLOCK “040904e4”

BEGIN

VALUE “CompanyName”, “TODO: <Company name>”

VALUE “FileDescription”, “TODO: <File description>”

VALUE “FileVersion”, “1.0.0.1”

VALUE “InternalName”, “UpdateIp.exe”

VALUE “LegalCopyright”, “TODO: (c) <Company name>.  All rights reserved.”

VALUE “OriginalFilename”, “UpdateIp.exe”

VALUE “ProductName”, “TODO: <Product name>”

VALUE “ProductVersion”, “1.0.0.1”

END

END

BLOCK “VarFileInfo”

BEGIN

VALUE “Translation”, 0x409, 1252

END

END

 

 

/////////////////////////////////////////////////////////////////////////////

//

// DESIGNINFO

//

 

#ifdef APSTUDIO_INVOKED

GUIDELINES DESIGNINFO

BEGIN

IDD_ABOUTBOX, DIALOG

BEGIN

LEFTMARGIN, 7

RIGHTMARGIN, 228

TOPMARGIN, 7

BOTTOMMARGIN, 48

END

 

IDD_UPDATEIP_DIALOG, DIALOG

BEGIN

RIGHTMARGIN, 142

END

END

#endif    // APSTUDIO_INVOKED

 

 

/////////////////////////////////////////////////////////////////////////////

//

// String Table

//

 

STRINGTABLE

BEGIN

IDS_ABOUTBOX            “&About UpdateIp…”

IDP_SOCKETS_INIT_FAILED “Windows sockets initialization failed.”

END

 

#endif    // Chinese (P.R.C.) resources

/////////////////////////////////////////////////////////////////////////////

 

 

 

#ifndef APSTUDIO_INVOKED

/////////////////////////////////////////////////////////////////////////////

//

// Generated from the TEXTINCLUDE 3 resource.

//

#define _AFX_NO_SPLITTER_RESOURCES

#define _AFX_NO_OLE_RESOURCES

#define _AFX_NO_TRACKER_RESOURCES

#define _AFX_NO_PROPERTY_RESOURCES

 

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)

LANGUAGE 4, 2

#pragma code_page(936)

#include “res\UpdateIp.rc2”  // non-Microsoft Visual C++ edited resources

#include “afxres.rc”     // Standard components

#endif

 

/////////////////////////////////////////////////////////////////////////////

#endif    // not APSTUDIO_INVOKED

 

 

UpdateIpDlg.h

// UpdateIpDlg.h : header file

//

 

#pragma once

 

 

// CUpdateIpDlg dialog

class CUpdateIpDlg : public CDialog

{

// Construction

public:

CUpdateIpDlg(CWnd* pParent = NULL);        // standard constructor

 

// Dialog Data

enum { IDD = IDD_UPDATEIP_DIALOG };

 

protected:

virtual void DoDataExchange(CDataExchange* pDX);        // DDX/DDV support

 

 

// Implementation

protected:

HICON m_hIcon;

 

// Generated message map functions

virtual BOOL OnInitDialog();

afx_msg void OnSysCommand(UINT nID, LPARAM lParam);

afx_msg void OnPaint();

afx_msg HCURSOR OnQueryDragIcon();

DECLARE_MESSAGE_MAP()

public:

afx_msg void OnBnClickedBtnStartservice();

afx_msg void OnBnClickedBtnStopservice();

afx_msg void OnTimer(UINT_PTR nIDEvent );

afx_msg void OnDestroy();

BOOL OnEraseBkgnd(CDC* pDC);

int OnCreate(LPCREATESTRUCT lpCreateStruct);

LRESULT OnNotifyIcon(WPARAM wParam,LPARAM IParam);

 

private:

void startService(int interval);

void stopService();

 

void startUpdateInstance();

void stopUpdateInstance();

 

BOOL setAutoStart(BOOL bVal);

void initSettings();

BOOL saveSettings();

CString getSettingFilePath();

void addNotification();

 

 

 

public:

afx_msg void OnBnClickedSave();

 

private:

int m_nTimer;

BOOL m_bAutoStart;

int m_nUpdateInterval;

int m_bIsRunning;

CString m_strSettingFilepath;

NOTIFYICONDATA NotifyIcon;

};

 

 

UpdateIpDlg.cpp

// UpdateIpDlg.cpp : implementation file

//

 

#include “stdafx.h”

#include “UpdateIp.h”

#include “UpdateIpDlg.h”

#include “lib/happyhttp.h”

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

#define WM_NC (WM_USER+1001)

const int TIMER_UPDATE = 100;

const TCHAR c_szSettingFilename[] = _T(“updateip.ini”);

const int c_nDefaultUpdate = 300;

const char c_szRequestHost[] = “xx.sinaapp.com”;     //换成自己的域名

 

// CAboutDlg dialog used for App About

 

class CAboutDlg : public CDialog

{

public:

CAboutDlg();

 

// Dialog Data

enum { IDD = IDD_ABOUTBOX };

 

protected:

virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

 

// Implementation

protected:

DECLARE_MESSAGE_MAP()

};

 

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)

{

}

 

void CAboutDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

}

 

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)

END_MESSAGE_MAP()

 

 

// CUpdateIpDlg dialog

 

 

 

 

CUpdateIpDlg::CUpdateIpDlg(CWnd* pParent /*=NULL*/)

: CDialog(CUpdateIpDlg::IDD, pParent)

, m_nTimer(0)

, m_bAutoStart(TRUE)

, m_nUpdateInterval(c_nDefaultUpdate)

, m_bIsRunning(FALSE)

, m_strSettingFilepath(_T(“”))

{

m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

 

void CUpdateIpDlg::DoDataExchange(CDataExchange* pDX)

{

CDialog::DoDataExchange(pDX);

}

 

BEGIN_MESSAGE_MAP(CUpdateIpDlg, CDialog)

ON_WM_SYSCOMMAND()

ON_WM_PAINT()

ON_WM_QUERYDRAGICON()

ON_WM_TIMER()

ON_WM_DESTROY()

ON_WM_CREATE()

ON_WM_ERASEBKGND()

//}}AFX_MSG_MAP

ON_BN_CLICKED(IDC_BTN_STARTSERVICE, &CUpdateIpDlg::OnBnClickedBtnStartservice)

ON_BN_CLICKED(IDC_BTN_STOPSERVICE, &CUpdateIpDlg::OnBnClickedBtnStopservice)

ON_BN_CLICKED(IDC_SAVE, &CUpdateIpDlg::OnBnClickedSave)

ON_MESSAGE(WM_NC,OnNotifyIcon)

END_MESSAGE_MAP()

 

 

// CUpdateIpDlg message handlers

 

BOOL CUpdateIpDlg::OnInitDialog()

{

CDialog::OnInitDialog();

 

// Add “About…” menu item to system menu.

 

// IDM_ABOUTBOX must be in the system command range.

ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);

ASSERT(IDM_ABOUTBOX < 0xF000);

 

CMenu* pSysMenu = GetSystemMenu(FALSE);

if (pSysMenu != NULL)

{

CString strAboutMenu;

strAboutMenu.LoadString(IDS_ABOUTBOX);

if (!strAboutMenu.IsEmpty())

{

pSysMenu->AppendMenu(MF_SEPARATOR);

pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);

}

}

 

// Set the icon for this dialog.  The framework does this automatically

//  when the application’s main window is not a dialog

SetIcon(m_hIcon, TRUE);                        // Set big icon

SetIcon(m_hIcon, FALSE);                // Set small icon

 

// TODO: Add extra initialization here

initSettings();

 

GetDlgItem(IDC_BTN_STARTSERVICE)->EnableWindow(FALSE);

GetDlgItem(IDC_BTN_STOPSERVICE)->EnableWindow(TRUE);

 

m_bIsRunning = TRUE;

startService(m_nUpdateInterval);

startUpdateInstance();

 

return TRUE;  // return TRUE  unless you set the focus to a control

}

 

void CUpdateIpDlg::OnSysCommand(UINT nID, LPARAM lParam)

{

if ((nID & 0xFFF0) == IDM_ABOUTBOX)

{

CAboutDlg dlgAbout;

dlgAbout.DoModal();

}else if ((nID & 0xFFF0) == SC_MINIMIZE )

{

ShowWindow(SW_HIDE);

}

else

{

CDialog::OnSysCommand(nID, lParam);

}

}

 

// If you add a minimize button to your dialog, you will need the code below

//  to draw the icon.  For MFC applications using the document/view model,

//  this is automatically done for you by the framework.

 

void CUpdateIpDlg::OnPaint()

{

if (IsIconic())

{

CPaintDC dc(this); // device context for painting

 

SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

 

// Center icon in client rectangle

int cxIcon = GetSystemMetrics(SM_CXICON);

int cyIcon = GetSystemMetrics(SM_CYICON);

CRect rect;

GetClientRect(&rect);

int x = (rect.Width() – cxIcon + 1) / 2;

int y = (rect.Height() – cyIcon + 1) / 2;

 

// Draw the icon

dc.DrawIcon(x, y, m_hIcon);

}

else

{

CDialog::OnPaint();

}

}

 

// The system calls this function to obtain the cursor to display while the user drags

//  the minimized window.

HCURSOR CUpdateIpDlg::OnQueryDragIcon()

{

return static_cast<HCURSOR>(m_hIcon);

}

 

 

 

 

void CUpdateIpDlg::OnBnClickedBtnStartservice()

{

// TODO: Add your control notification handler code here

GetDlgItem(IDC_BTN_STARTSERVICE)->EnableWindow(FALSE);

GetDlgItem(IDC_BTN_STOPSERVICE)->EnableWindow(TRUE);

startService(m_nUpdateInterval);

}

 

void CUpdateIpDlg::OnBnClickedBtnStopservice()

{

// TODO: Add your control notification handler code here

GetDlgItem(IDC_BTN_STARTSERVICE)->EnableWindow(TRUE);

GetDlgItem(IDC_BTN_STOPSERVICE)->EnableWindow(FALSE);

stopService();

}

 

void CUpdateIpDlg::OnTimer(UINT_PTR nIDEvent ){

startUpdateInstance();

}

 

void CUpdateIpDlg::OnDestroy(){

Shell_NotifyIcon(NIM_DELETE, &NotifyIcon);

 

return CDialog::OnDestroy();

}

 

BOOL CUpdateIpDlg::OnEraseBkgnd(CDC* pDC){

 

static bool bFirst=true;

if(bFirst)

{

bFirst=false;

ShowWindow(SW_HIDE);

return TRUE;

}

 

return CDialog::OnEraseBkgnd(pDC);

}

 

int CUpdateIpDlg::OnCreate(LPCREATESTRUCT lpCreateStruct){

addNotification();

 

return CDialog::OnCreate(lpCreateStruct);

}

 

void CUpdateIpDlg::startService(int interval){

m_nTimer = SetTimer(TIMER_UPDATE,interval * 1000,0);

m_bIsRunning = TRUE;

 

CString strResult;

GetDlgItemText(IDC_EDIT_RESULT,strResult);

strResult += _T(“startService:\r\n”);

SetDlgItemText(IDC_EDIT_RESULT,strResult);

}

 

void CUpdateIpDlg::stopService(){

KillTimer(m_nTimer);

stopUpdateInstance();

m_bIsRunning = FALSE;

 

CString strResult;

GetDlgItemText(IDC_EDIT_RESULT,strResult);

strResult += _T(“stopService:\r\n”);

SetDlgItemText(IDC_EDIT_RESULT,strResult);

}

 

int count=0;

 

void OnBegin( const happyhttp::Response* r, void* userdata )

{

printf( “BEGIN (%d %s)\n”, r->getstatus(), r->getreason() );

count = 0;

}

 

void OnData( const happyhttp::Response* r, void* userdata, const unsigned char* data, int n )

{

fwrite( data,1,n, stdout );

count += n;

}

 

void OnComplete( const happyhttp::Response* r, void* userdata )

{

printf( “COMPLETE (%d bytes)\n”, count );

}

 

void CUpdateIpDlg::startUpdateInstance(){

//启动新的线程去发起Http请求

stopUpdateInstance();

CString strResult;

GetDlgItemText(IDC_EDIT_RESULT,strResult);

strResult += _T(“启动更新请求:\r\n”);

SetDlgItemText(IDC_EDIT_RESULT,strResult);

 

try

{

char uid[] = “0000”;

char szTemp[1024] = {0};

_snprintf_s(szTemp,sizeof(szTemp),sizeof(szTemp),”/updateip.php?m=update&uid=%s”,uid);

 

 

happyhttp::Connection conn(c_szRequestHost, 80 );

conn.setcallbacks( OnBegin, OnData, OnComplete, 0 );

 

conn.request( “GET”, szTemp, 0, 0,0 );

 

while( conn.outstanding() )

conn.pump();

 

/*

TCHAR uid[] = _T(“0000”);

TCHAR szTemp[1024] = {0};

_sntprintf_s(szTemp,sizeof(szTemp),sizeof(szTemp),_T(“/updateip.php?m=update&uid=%s”),uid);

 

 

BOOL  bResults = FALSE;

HINTERNET hSession = NULL,

hConnect = NULL,

hRequest = NULL;

 

// Use WinHttpOpen to obtain a session handle.

hSession = WinHttpOpen(  L”A WinHTTP Example Program/1.0″,

WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,

WINHTTP_NO_PROXY_NAME,

WINHTTP_NO_PROXY_BYPASS, 0);

 

// Specify an HTTP server.

if (hSession)

hConnect = WinHttpConnect( hSession, c_szRequestHost,

INTERNET_DEFAULT_HTTP_PORT, 0);

 

// Create an HTTP Request handle.

if (hConnect)

hRequest = WinHttpOpenRequest( hConnect, L”PUT”, szTemp,

NULL, WINHTTP_NO_REFERER,

WINHTTP_DEFAULT_ACCEPT_TYPES, 0);

 

// Send a Request.

if (hRequest)

bResults = WinHttpSendRequest( hRequest,

WINHTTP_NO_ADDITIONAL_HEADERS, 0,

WINHTTP_NO_REQUEST_DATA, 0,

0, 0);

 

// Place additional code here.

 

 

// Report errors.

if (!bResults{

CString strResult;

GetDlgItemText(IDC_EDIT_RESULT,strResult);

strResult += _T(“请求发送失败,URL = “);

strResult += c_szRequestHost;

strResult += szTemp;

strResult += “\r\n”;

SetDlgItemText(IDC_EDIT_RESULT,strResult);

}else{

CString strResult;

GetDlgItemText(IDC_EDIT_RESULT,strResult);

strResult += _T(“请求发送成功,URL = “);

strResult += c_szRequestHost;

strResult += szTemp;

strResult += “\r\n”;

SetDlgItemText(IDC_EDIT_RESULT,strResult);

}

printf(“Error %d has occurred.\n”,GetLastError());

 

 

 

// Close open handles.

if (hRequest) WinHttpCloseHandle(hRequest);

if (hConnect) WinHttpCloseHandle(hConnect);

if (hSession) WinHttpCloseHandle(hSession);*/

}catch( happyhttp::Wobbly& e )

{

printf(“Exception:\n%s\n”, e.what() );

}

 

 

}

 

void CUpdateIpDlg::stopUpdateInstance(){

CString strResult;

GetDlgItemText(IDC_EDIT_RESULT,strResult);

strResult += _T(“停止更新请求:\r\n”);

SetDlgItemText(IDC_EDIT_RESULT,strResult);

 

}

 

BOOL CUpdateIpDlg::setAutoStart(BOOL bVal){

HKEY hKey;

long return_val = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L”Software\\Microsoft\\Windows\\CurrentVersion\\Run”,0,KEY_READ| KEY_WRITE,&hKey );

if (ERROR_SUCCESS == return_val)

{

if (bVal)

{

TCHAR pathtofile[MAX_PATH] = {0};

GetModuleFileName(NULL,pathtofile,MAX_PATH);

 

if (ERROR_SUCCESS != RegSetValueEx(hKey,_T(“autoupdateip”),0,REG_SZ,(byte *)pathtofile,sizeof(pathtofile)))

{

RegCloseKey(hKey);

return FALSE;

}

 

}else{

long ret = RegDeleteValue(hKey,_T(“autoupdateip”));

if (ERROR_SUCCESS != ret && ret != ERROR_FILE_NOT_FOUND)

{

int err = GetLastError();

 

RegCloseKey(hKey);

return FALSE;

}

}

 

RegCloseKey(hKey);

 

return TRUE;

 

}

 

return FALSE;

}

 

void CUpdateIpDlg::OnBnClickedSave()

{

// TODO: Add your control notification handler code here

m_bAutoStart = ((CButton *)GetDlgItem(IDC_CHECK_AUTOSTART))->GetCheck();

if (!setAutoStart(m_bAutoStart))

{

MessageBox(_T(“setAutoStart error!”));

}

 

 

m_nUpdateInterval = GetDlgItemInt(IDC_EDIT_UPDATEINTERVAL);

if (m_bIsRunning)

{

stopService();

startService(m_nUpdateInterval);

}

 

if(!saveSettings()){

MessageBox(_T(“saveSettings error!”));

}else{

MessageBox(_T(“saveSettings Success!”));

}

}

 

void CUpdateIpDlg::initSettings(){

m_strSettingFilepath = getSettingFilePath();

m_bAutoStart = (BOOL)GetPrivateProfileInt(_T(“config”),_T(“autostart”),1,m_strSettingFilepath);

m_nUpdateInterval = GetPrivateProfileInt(_T(“config”),_T(“updateinterval”),c_nDefaultUpdate,m_strSettingFilepath);

 

((CButton *)GetDlgItem(IDC_CHECK_AUTOSTART))->SetCheck(m_bAutoStart);

if (!setAutoStart(m_bAutoStart))

{

MessageBox(_T(“setAutoStarterror”));

}

 

SetDlgItemInt(IDC_EDIT_UPDATEINTERVAL,m_nUpdateInterval);

}

 

BOOL CUpdateIpDlg::saveSettings(){

CString strTemp;

strTemp.Format(_T(“%d”),m_bAutoStart);

if (!WritePrivateProfileString(_T(“config”),_T(“autostart”),strTemp,m_strSettingFilepath))

{

return FALSE;

}

 

strTemp.Format(_T(“%d”), m_nUpdateInterval);

if (!WritePrivateProfileString(_T(“config”),_T(“updateinterval”),strTemp,m_strSettingFilepath))

{

return FALSE;

}

 

return TRUE;

}

 

CString CUpdateIpDlg::getSettingFilePath(){

TCHAR szPath[MAX_PATH] = {0};

BOOL bRet = SHGetSpecialFolderPath(NULL,szPath,CSIDL_APPDATA,FALSE);

if (!bRet)

{

MessageBox(_T(“SHGetSpecialFolderPath Failed!”));

return _T(“”);

}

 

CString strFolder = szPath;

strFolder += “\\autoupdateip\\“;

if (!CreateDirectory(strFolder,NULL) && GetLastError() != ERROR_ALREADY_EXISTS)

{

MessageBox(_T(“创建临时目录失败!”));

return _T(“”);

}

 

return strFolder + c_szSettingFilename;

 

}

 

LRESULT CUpdateIpDlg::OnNotifyIcon(WPARAM wParam,LPARAM IParam)

{

if ((IParam == WM_LBUTTONDOWN) || (IParam == WM_RBUTTONDOWN))

{

ModifyStyleEx(0,WS_EX_TOPMOST);

ShowWindow(SW_RESTORE);

//Shell_NotifyIcon(NIM_DELETE, &NotifyIcon);

}

 

return 0;

}

 

void CUpdateIpDlg::addNotification(){

NotifyIcon.cbSize=sizeof(NOTIFYICONDATA);

NotifyIcon.hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);

NotifyIcon.hWnd=m_hWnd;

lstrcpy(NotifyIcon.szTip,_T(“Auto Update IP by weibin”));

NotifyIcon.uCallbackMessage=WM_NC;

NotifyIcon.uFlags=NIF_ICON | NIF_MESSAGE | NIF_TIP;

Shell_NotifyIcon(NIM_ADD,&NotifyIcon);

}

 

 

通过admin

利用ctags,实现应用库函数的跳转

首先安装ctags,安装过程网上很多,就不多讲,安装之后执行ctags -R,就可以在本项目内实现代码跳转了,但不能跳转到不是在本项目的代码中定义的tag。例如在上面的图中,本地定义了一个类A,在main函数中定义了一个A类的对象,我们可以按“Ctrl+]”组合键跳转到class A那一行。然后可以按“Ctrl+O”跳转回来。

如果想实现跳转到非本项目的tag,则必须让Vim知道这些tag在哪。刚才的项目在/home/user/code/目录下,现在假设又有一个项目在/home/user/program/下,那么我们需要在此项目下生成program这个项目的tags文件(还是用上面的ctags命令)。

生成之后,要告知Vim,需要在Vim的配置文件中(/home/user/.vimrc)添加下面的内容:

” — ctags setting —
set tags=tags
set tags+=./tags        ” add current directory’s generated tags file
set tags+=~/program/tags ” add new tags file

最后一行就表示在搜寻tags文件的时候,也要搜寻/home/user/program/文件夹下的tags文件。保存以后重启,此时应该就能实现不同项目间的跳转了。这是因为我们经常会基于一些库开发软件,我们需要查看库中函数或者类的定义的时候,会经常需要此功能。

 

 

例如最近在用的protobuf库,首先进入到该库的代码路径:cd /home/user/protobuf2.41

,执行ctags -R,生成tags,然后编辑sudo vim /etc/vim/vimrc,在末尾添加:

” — ctags setting —
set tags=tags
set tags+=./tags        ” add current directory’s generated tags file
set tags+=~/protobuf2.41 ” add new tags file

 

重新打开vim,就发现以前跳转不过去的函数现在也可以跳转了。在vim的命令行状态也可以执行:set tags+=~/protobuf2.41临时加载一个tags,但是只在本次有效。

通过admin

跟我一起写 Makefile

概述

——

什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些 Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile 了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。

因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。

makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

现在讲述如何写makefile的文章比较少,这是我想写这篇文章的原因。当然,不同产商的 make各不相同,也有不同的语法,但其本质都是在“文件依赖性”上做文章,这里,我仅对GNU的make进行讲述,我的环境是RedHat Linux 8.0,make的版本是3.80。必竟,这个make是应用最为广泛的,也是用得最多的。而且其还是最遵循于IEEE 1003.2-1992 标准的(POSIX.2)。

在这篇文档中,将以C/C++的源码作为我们基础,所以必然涉及一些关于C/C++的编译的知识,相关于这方面的内容,还请各位查看相关的编译器的文档。这里所默认的编译器是UNIX下的GCC和CC。

 

关于程序的编译和链接

——————————

在此,我想多说关于程序编译的一些规范和方法,一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows下也就是 .obj 文件,UNIX下是 .o 文件,即 Object File,这个动作叫做编译(compile)。然后再把大量的Object File合成执行文件,这个动作叫作链接(link)。

编译时,编译器需要的是语法的正确,函数与变量的声明的正确。对于后者,通常是你需要告诉编译器头文件的所在位置(头文件中应该只是声明,而定义应该放在C/C++文件中),只要所有的语法正确,编译器就可以编译出中间目标文件。一般来说,每个源文件都应该对应于一个中间目标文件(O文件或是OBJ文件)。

链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O文件或是OBJ文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows下这种包叫“库文件”(Library File),也就是 .lib 文件,在UNIX下,是Archive File,也就是 .a 文件。

总结一下,源文件首先会生成中间目标文件,再由中间目标文件生成执行文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的Object File.

好,言归正传,GNU的make有许多的内容,闲言少叙,还是让我们开始吧。

 

Makefile 介绍

———————

make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。

首先,我们用一个示例来说明Makefile的书写规则。以便给大家一个感兴认识。这个示例来源于GNU的make使用手册,在这个示例中,我们的工程有8个C文件,和3个头文件,我们要写一个Makefile来告诉make命令如何编译和链接这几个文件。我们的规则是:

1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。

2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。

3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。

只要我们的Makefile写得够好,所有的这一切,我们只用一个make命令就可以完成,make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。

 

一、Makefile的规则

在讲述这个Makefile之前,还是让我们先来粗略地看一看Makefile的规则。

target … : prerequisites …

command

target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。

prerequisites就是,要生成那个target所需要的文件或是目标。

command也就是make需要执行的命令。(任意的Shell命令)

这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于 prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比 target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

说到底,Makefile的东西就是这样一点,好像我的这篇文档也该结束了。呵呵。还不尽然,这是Makefile的主线和核心,但要写好一个Makefile还不够,我会以后面一点一点地结合我的工作经验给你慢慢到来。内容还多着呢。:)

 

二、一个示例

正如前面所说的,如果一个工程有3个头文件,和8个C文件,我们为了完成前面所述的那三个规则,我们的Makefile应该是下面的这个样子的。

edit : main.o kbd.o command.o display.o /

insert.o search.o files.o utils.o

cc -o edit main.o kbd.o command.o display.o /

insert.o search.o files.o utils.o

main.o : main.c defs.h

cc -c main.c

kbd.o : kbd.c defs.h command.h

cc -c kbd.c

command.o : command.c defs.h command.h

cc -c command.c

display.o : display.c defs.h buffer.h

cc -c display.c

insert.o : insert.c defs.h buffer.h

cc -c insert.c

search.o : search.c defs.h buffer.h

cc -c search.c

files.o : files.c defs.h buffer.h command.h

cc -c files.c

utils.o : utils.c defs.h

cc -c utils.c

clean :

rm edit main.o kbd.o command.o display.o /

insert.o search.o files.o utils.o

反斜杠(/)是换行符的意思。这样比较便于Makefile的易读。我们可以把这个内容保存在文件为“Makefile”或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文件edit。如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“make clean”就可以了。

在这个makefile中,目标文件(target)包含:执行文件edit和中间目标文件(*.o),依赖文件(prerequisites)就是冒号后面的那些 .c 文件和 .h文件。每一个 .o 文件都有一组依赖文件,而这些 .o 文件又是执行文件 edit 的依赖文件。依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。

在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab 键作为开头。记住,make并不管命令是怎么工作的,他只管执行所定义的命令。make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。

这里要说明一点的是,clean不是一个文件,它只不过是一个动作名字,有点像C语言中的 lable一样,其冒号后什么也没有,那么,make就不会自动去找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make 命令后明显得指出这个lable的名字。这样的方法非常有用,我们可以在一个makefile中定义不用的编译或是和编译无关的命令,比如程序的打包,程序的备份,等等。

 

源文档 <http://blog.csdn.net/haoel/article/details/2886>

 

通过admin

linux下Google的Protobuf安装及使用笔记

protobuf

项目主页:http://code.google.com/p/protobuf/

下载:http://code.google.com/p/protobuf/downloads/list protobuf-2.4.1.tar.gz

解压后进入protobuf-2.4.1目录进行安装:

1、./configure(注:默认可能会安装在/usr/local目录下,可以加–prefix=/usr来指定安装到/usr/lib下,可以免去路径的设置,路径设置见Linux命令pkg-config

./configure –prefix=/usr/local/protobuf

2、make

3、make check

4、make install(需要超级用户root权限)

二、使用

1、写proto文件,定义消息具体格式。如:helloworld.proto

package lm;

message helloworld

{

required int32 id = 1;//ID

required string str = 2;//str

optional int32 opt = 3;//optional field

}

2、使用protoc来编译生成对应语言的文件

–cpp_out:表示输出c++语言使用格式,–java_out,–python_out等,其他第三方的插件:Third-Party Add-ons for Protocol Buffers

此时会生成helloworld.pb.h及helloworld.pb.cc两个文件

3、Write A message

View Code

4、Read A message

View Code

5、编译及运行

g++ -g -o Writer helloworld.pb.cc writermessage.cpp `pkg-config –cflags –libs protobuf`

g++ -g -o Reader helloworld.pb.cc Readermessage.cpp `pkg-config –cflags –libs protobuf`

通过admin

Protobuf C++ serialize到char*的方法

protobuf的Demo程序是

C++版本的protubuf有几种serialize和unSerialize的方法:

方法一:

官方demo程序采用的是

// Write the new address book back to disk.

fstream output(argv[1], ios::out | ios::trunc | ios::binary);

if (!address_book.SerializeToOstream(&output)) {

cerr << “Failed to write address book.” << endl;

return -1;

}

 

// Read the existing address book.

fstream input(argv[1], ios::in | ios::binary);

if (!input) {

cout << argv[1] << “: File not found.  Creating a new file.” << endl;

} else if (!address_book.ParseFromIstream(&input)) {

cerr << “Failed to parse address book.” << endl;

return -1;

}

 

 

上面采用的是fstream,把数据序列(反序列)打磁盘文件中。

 

而如果想序列到char *,并且通过socket传输,则可以使用:

方法二:

int size = address_book.ByteSize();

void *buffer = malloc(size);

address_book.SerializeToArray(buffer, size);

 

方法三:

使用ostringstream ,

std::ostringstream stream;

address_book.SerializeToOstream(&stream);

 

string text = stream.str();

char* ctext = string.c_str();

通过admin

详解Google-ProtoBuf中结构化数据的编码

原文:http://www.wuzesheng.com/?p=1258

本文的主要内容是google protobuf中序列化数据时用到的编码规则,但是,介绍具体的编码规则之前,我觉得有必要先简单介绍一下google protobuf。因此,本文首先会介绍一些google protobuf相关的内容,让读者朋友对google protobuf有一个初步的印象,然后,再开始进入正题—-深入浅出地介绍google protobuf中用到的编码规则。下面言归正传,开始今天的话题。

1. Google-ProtoBuf是什么

ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf。

ProtoBuf可以支持多种编程语言,目前已经C++, Java和Python,本文中所前的内容用到例子的话,会以C++为例。

2.如何得到Google-ProtoBuf

ProtoBuf在Google Code上的主页是:http://code.google.com/p/protobuf/, 感兴趣的朋友可以在这里下载ProtoBuf的源码,也可以在这里阅读ProtoBuf的详细的文档。

3. 深入浅出Google-ProtoBuf中的编码规则

(1)序列化和反序列化:

在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化。这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不太好理解,在这里我会用比较通俗的文字来解释,尽可能让读都朋友们一读就明白是怎么回事:

序列化:是指将结构化的数据按一定的编码规范转成指定格式的过程

反序列化:是指将转成指定格式的数据解析成原始的结构化数据的过程

举个例子,Person是一个表示人的对象类型,person是一个Person类型的对象,将person存到一个对应的XML文档中的过程就是一种序列化,而解析XML生成对应Person类型对象person的过程,就是一个反序列化的过程。在这里结构化数据指的就是Person类型的数据,一定的编码规范指的就是XML文档的规范。XML是一种简单的序列化方式,用XML序列化的好处是,XML的通用性比较好,另外,XML是一种文本格式,对人阅读比较友好,但是XML方式比较占空间,效率也不是很高。通常,比较高效的序列化都是采用二进制方式的,将要序列化的结构化数据,按一定的编码规范,转成为一串二进制的字节流存储下来,需要用的时候再从这串二进制的字节流中反序列化出对应的结构化的数据。

通过上面的介绍,我们给protobuf下一个比较正式的定义了:Google ProtoBuf是Google制定的一种用来序列化结构化数据的程序库。

(2)ProtoBuf中的编码:

1) ProtoBuf编码基础——Varints, varints是一种将一个整数序列化为一个或者多个Bytes的方法,越小的整数,使用的Bytes越少。

Varints的基本规则是:

(a)每个Byte的最高位(msb)是标志位,如果该位为1,表示该Byte后面还有其它Byte,如果该位为0,表示该Byte是最后一个Byte。

(b)每个Byte的低7位是用来存数值的位

(c)Varints方法用Litte-Endian(小端)字节序

举个例子:300用Varints序列化的结果是1010 1100 0000 0010,运算过程如下所示:

1010 1100 0000 0010->010 1100 000 0010(去标志位)->

000 0010 010 1100(调整字节序)-> 1 0010 1100 ->256+32+8+4=300(计算值)

2)ProtoBuf中消息的编码规则:

(a)每条消息(message)都是有一系列的key-value对组成的, key和value分别采用不同的编码方式。

(b)对某一条件消息(message)进行编码的时候,是把该消息中所有的key-value对序列化成二进制字节流;而解码的时候,解码程序读入二进制的字节流,解析出每一个key-value对,如果解码过程中遇到识别不出来的类型,直接跳过。这样的机制,保证了即使该消息添加了新的字段,也不会影响旧的编/解码程序正常工作。

(c)key由两部分组成,一部分是在定义消息时对字段的编号(field_num),另一部分是字段类型(wire_type)。字段类型定义如下表所示。

Type Meaning Used For
0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
1 64-bit fixed64, sfixed64, double
2 Length-delimited string, bytes, embedded messages, packed repeated fields
3 Start group groups (deprecated)
4 End group groups (deprecated)
5 32-bit fixed32, sfixed32, float

(d)key的编码方式:field_num << 3 | wire_type

(e)varint类型(wire_type=0)的编码,与第(1)部分中介绍的方法基本一致,但是int32, int64和sint32,sint64有些特别之处:int32和int64就是简单的按varints方法来编码,所以像-1、-2这样负数也会占比较多的Bytes。于是sint32和sint64采用了一种改进的方法:先采用Zigzag方法将所有的整数(正数、0和负数)一一映射到所有的无符号数上,然后再采用varints编码方法进行编码。Zigzag映射函数为:

Zigzag(n) = (n << 1) ^ (n >> 31),  n为sint32时

Zigzag(n) = (n << 1) ^ (n >> 63),  n为sint64时

下表是一个比较直观的映射表,这样映射后再进行编码的好处就是绝对值比较小的负数序列化后的结果占的Bytes数也会比较少。

Signed Original Encoded As
0 0
-1 1
1 2
-2 3
2 4
-3 5
2147483647 4294967294
-2147483648 4294967295

(f)64-bit(wire_type=1)和32-bit(wire_type=5)的编码方式就比较简单了,直接在key后面跟上64bits或32bits,采用Little-Endian(小端)字节序。

(g)length-delimited(wire_type=2)的编码方式:key+length+content, key的编码方式是统一的,length采用varints编码方式,content就是由length指定的长度的Bytes。

(h)wire_type=3和4的现在已经不推荐使用了,因此这里也不再做介绍。

3)ProtoBuf编解码中字段顺序(Field order)的问题:

(a) 编码/解码与字段顺序无关,这一点由key-value机制就能保证

(b)对于未知的字段,编码的时候会把它写在序列化完的已知字段后面。

 

源文档 <http://www.wuzesheng.com/?p=1258>

通过admin

Java protobuf框架使用向导

 

ProtoBuf,全称是Protocol Buffers, 它是谷歌内部用的一种高效的、可扩展的对结构化数据进行编码的格式规范。谷歌自己内部很多程序之间的通信协议都用了ProtoBuf。

下面介绍的是使用Java ProtoBuf的基本步骤:

1.http://code.google.com/p/protobuf/downloads/list ,选择其中的win版本下载

2.下载一个protobuf-java-2.4.1.jar文件(注意,要与你刚才下的proto.exe版本相同,否则可能出现编译通不过现象)

http://grepcode.com/snapshot/repo1.maven.org/maven2/com.google.protobuf/protobuf-java/2.4.1

3.在proto.exe同级目录,编写一个msg.proto文件:

 

package tutorial;

 

option java_package = “com.protobuftest.protobuf”;

option java_outer_classname = “PersonProbuf”;

 

message Person {

required string name = 1;

required int32 id = 2;

optional string email = 3;

 

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

 

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];

}

 

repeated PhoneNumber phone = 4;

 

message CountryInfo {

required string name = 1;

required string code = 2;

optional int32 number = 3;

}

}

 

message AddressBook {

repeated Person person = 1;

}

 

4.使用如下命令编译这个文件:

5.将生成的ProtoBufferPractice.java文件引入eclipse

6.把下载的protobuf-java-2.4.1.jar也引入工程

7.使用方法:

package com.protobuftest;

 

import java.util.List;

 

import com.google.protobuf.InvalidProtocolBufferException;

import com.protobuftest.protobuf.PersonProbuf;

import com.protobuftest.protobuf.PersonProbuf.Person;

import com.protobuftest.protobuf.PersonProbuf.Person.PhoneNumber;

import com.protobuftest.protobuf.PersonProbuf.Person.PhoneNumberOrBuilder;

import com.protobuftest.protobuf.PersonProbuf.Person.PhoneType;

 

public class ProtoBufTest {

 

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

PersonProbuf.Person.Builder builder = PersonProbuf.Person.newBuilder();

builder.setEmail(“kkk@email.com”);

builder.setId(1);

builder.setName(“TestName”);

builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber(“131111111”).setType(PersonProbuf.Person.PhoneType.MOBILE));

builder.addPhone(PersonProbuf.Person.PhoneNumber.newBuilder().setNumber(“011111”).setType(PersonProbuf.Person.PhoneType.HOME));

 

Person person = builder.build();

byte[] buf = person.toByteArray();

 

try {

Person person2 = PersonProbuf.Person.parseFrom(buf);

System.out.println(person2.getName() + “, ” + person2.getEmail());

List<PhoneNumber> lstPhones = person2.getPhoneList();

for (PhoneNumber phoneNumber : lstPhones) {

System.out.println(phoneNumber.getNumber());

}

} catch (InvalidProtocolBufferException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

System.out.println(buf);

 

}

 

}

 

源文档 <http://blog.csdn.net/csharp25/article/details/6632127>

通过admin

第2章 进程及进程调度

几个关键字:

进程结构task_struct;系统task_stuct数组;

进程状态:

进程时间片;

进程切换时,系统需要做那些保存操作;

进程创建过程,fork();

工作队列;

进程调度。

通过admin

《Linux内核分析及编程》第一章 数据类型及链表

本章完全是基础知识了,归纳下几点:

在不同的CPU体系结构上,C语言的数据类型所占的空间是不一样的;

为了方便移植,内核中很多数据类型由typedef声明;

内存页面大小;

字节对齐方式:低字节优先&高字节优先;

内核通用链表;

行内汇编的格式;

内核时间延迟;