分类 [ C/C++ ] 下的全部文章

VS2008/VS2010连接TFS 2012年1月01日


当管理人员建立好TFS服务器之后,其他工作人员便可以通过TFS的客户端来连接服务器了,在下面内容中,我们会提及到以下内容。

  • 如何连接TFS
  • 如何建立新的团队项目
  • 源代码保护
  • 如何管理项目文档
  • 如何通过Web形式访问项目门户

1. 如何连接TFS

对于非技术人员可以不安装TFS的客户端,而直接通过Web形式来访问团队门户,但如果是技术人,那么要确定IDE的版本,如果使用VS2010,则不需要额外安装,该功能已经集成在IDE中。如果使用的是VS2008,则需要安装TFS的客户端浏览器,将TFS的ISO加载到虚拟光驱中,并且运行setup.exe,在弹出的安装窗口中选择“Team Explorer”(团队浏览器),如下图所示:

Team Explorer安装完毕之后,打开VS IDE,在IDE的工具栏上会多出一个图标,如下图所示:

点击这个图标,就会打开团队管理器,如下图所示:

此时,请点击按钮,以添加新项目,点击之后,会弹出“Connect to Team Foundation Server”(连接到TFS)对话框,如下图所示:

点击“Servers”按钮,会弹出“Add/Remove Team Foundation Server”对话框,如下图所示:

点击“Add”按钮,添加新的服务器,这里只需要输入服务器的IP即可,路径,商品号以及协议均采用默认,如下图所示:

配置完毕之后,点击“OK”,便可以进行首次连接,如下图所示:

连接完毕后的效果,如下图所示:

2. 如何建立新的团队项目

在服务器名称上点右键,在弹出的菜单上选择“New Team Project”,如下图所示:

在弹出的窗口中,首先输入项目的名称,如下图所示:

然后选择项目管理过程的模板,如下图所示:

默认的模板是MS的敏捷方式模板,同时还为用户提供了基于CMMI的标准管理模板(两种管理方式的区别是一个比较大的话题,我们会在以后的Blog中时行分类讲解),这里选择敏捷开发方式模板。

接下来,要设置项目门户的标题以及供述,同时自动生成一个门户网址(用户可以通过门户方式对项目进行管理,不需要安装TFS客户端),如下图所示:

下面,来选择源代码管理的文件夹名,这里采用默认名称,如下图所示:

最后点击下一步,完成。新项目建立完毕之后,团队管理器如下图所示:

从上图中可以看出,通过设置敏捷开发方式,系统为用户自动生成了对应的工具模板,其中包括:工作项文件夹(主要用于工作项的传递以及追踪),文档文件夹(用于开发人员之间文档的传递),报表文件夹(用来存储项目相关的报表,如进度报表等),编译方案文件夹(用来配置MS Build,以定制编译方案)以及源代码控制。

3. 源代码保护

下面我们在VS2010中建立一个解决方案,并添加几个项目,然后把这些项目的源代码签入到刚才建立的TFS上。

首先,要将VS连接到刚才建立好的TFS上(方法和前面所讲的一样,这里不再重复),然后建立几个项目,如下图所示:

其中,MyProject.Web是应用系统的表现层,MyProject.Bl是业务逻辑层,MyProject.DA是数据访问层。下面在MyProject的解决方案上点击右键,在弹出的菜单下点击“Add To Source Control”,如下图所示:

在弹出的窗口中选择对应的项目(这里是TestProject),并确定,如下图所示:

这里,我们会在解决方案窗口中发现所有的项目前面都有一个图标,这表明现在所有的项目还没有被签入过,如下图所示:

代码的签入比较简单,只需要在解决方案上点击右键,选择“CheckIn”即可,如下图所示:

这时系统会为用户提示要签入的文件,如下图所示:

点击“CheckIn”按钮后,代码文件会被签入,同时代码的图标也会变成,表示代码已经被锁定,不能更改。

如果需要修改代码,并且别人不能同时修改,可以将代码签出,此时,右键点击要签出的文件,选择“CheckOut For Edit”,如下图所示:

然后会弹出文件签出窗口,然后在LockType选项中选择第二项,即当前用户可以修改,其他用户不能修改,最后点击“CheckOut”按钮,如下图所示:

被签出的代码文件的图标会变成,如下图所示:

如果想在其他用户的计算机上打开源代码,首先,连接远程TFS,方法和前面所说的连接方法一样,然后在Team Explorer双击“Source Control”,如下图所示:

这时会打开当前团队项目的“Source Control Explorer”,找到对应的解决方案文件,打开即可,如下图所示:

4. 如何管理项目文档

展开Team Explorer的“Documents”文件夹,我们可以看到系统已经为用户自动生成好了一系统列的文档模板,其中包括几个Excel和Project文件模板,如下图所示:

此时可以直接打开并编辑。

同时,你也可以新新建立文档,并上传,只要在对应的文件夹上点击右键,在弹出的菜单中点击“Upload Document”,如下图所示:

这样,您的文档就可以被其他人共享。

5. 如何通过Web形式访问项目门户

在Team Explorer中选择对应的项目,在右键弹出菜单中选择“Show Project Portal”,如下图所示:

此时项目的门户的页面就会被打开,如下图所示:

该门户基本上可以实现和Team Explorer相同的功能,非技术人员可以通过些种方式来进行项目管理。

 

TIOBE 于今日公布了2011年12月编程语言排行榜,虽然前三的位置还是Java、C 和 C++,但是第三位置恐将很快易主。

从2001年开始,TIOBE指数排行榜第三的这个位置,C++编程语言一直坐的比较稳定。虽然Perl、Visual Basic和PHP曾经也位居第三,但它们坚持的时间仅有数月。现如今,C#就要叩响第三位置的大门了(C#和C++之间的Ratings差距不到 0.05%)。这又将是一场硬仗了,我们将在未来数月内看到结果了。

编注:C#是微软推出的一种基于.NET框架的、面向对象的高级编程语言。C#由C语言和C++派生而来,继承了其强大的性能,同时又以.NET 框架类库作为基础,拥有类似Visual Basic的快速开发能力。C#由安德斯·海尔斯伯格主持开发,微软在2000年发布了这种语言。

此外,Objective-C在本期中又上升至第5位,上个月是第6位。Logo语言从业上月的第21位升至第18位。

2011年12月编程语言排行榜 Top 20 具体榜单

2011年12月编程语言排行榜 Top 20

 

USB 应用开发鸟瞰 2011年3月26日

借助于Linux系统先进的设备管理策略,开发与usb设备通信的应用程序就比较简单——就是打开usb设备获取设备句柄、然后读写句柄、最后就是关闭句柄了。不过在内核层,操作就复杂了,对于应用层递交下来的操作,要依次穿过内核层中的USB设备驱动、USB驱动和USB主控制器驱动,但是作为应用程序开发员来说,他可以不用关心这些细节。

在通用Linux系统中,usb控制芯片驱动(uhci.o|usb-ohci.o|ehci-hcd.o)和usb核心驱动(usbcore.o)都是已经准备好了的,可以随时加载,而对于大多数通用的usb设备,相应的驱动也已经以模块文件的形式安装了,当插入usb设备时自动加载这些模块(比如u盘的驱动usb-storage.o,usb鼠标的驱动usbmouse.o、mousedev.o以及usb键盘驱动usbkbd.o、keybdev.o等等)。

如果usb设备是自己开发的且不是通用的,那么就要自己编写的usb设备驱动了,对于如何编写usb设备驱动,超出了本文要讨论的范围(感兴趣的同仁可以参考linux内核源码树下的usb驱动框架文件drivers/usb/usb-skeleton.c,顺便提一下:对于开发pci插卡的设备驱动框架可以参考这个drivers/net/pci-skeleton.c)。鸟瞰图如下:

windows shell扩展不像一般的应用程序,调试比较麻烦,因此建立远程调试是必须的,我自己写了个windows shell namespace extension程序(把sftp服务器上的目录映射到windows的桌面名字空间)。下面我据悉讲讲如何搭建一个远程调试环境:

目标机:运行被调试程序的那台电脑;一般使用虚拟机。
调试机:运行vs2008的那台电脑; 一般使用物理机。

一、VMware:

如果目标机器是虚拟机,那么最好安装Vmware Tools,菜单“虚拟机-->安装VMware Tools”,如果报“更新服务器的证书错误,请检查你的网络设置或与你的系统管理员联系”错误而不能安装,那么按如下方式操作进行安装:找到vmware安装目录下的文件VMware Tools 6.0.iso(比如我的机器这个文件位于目录C:\Program Files\VMware Workstation 7\Tool下),通过winrar把它解压并拷贝到虚拟机里进行安装(运行里面的setup.exe),最后重启。这样主机与虚拟机文件传送直接采用粘贴拷贝就行了。

二、VS2008远程调试:

1、在目标机上安装远程调试器: 解压vs2008的iso文件或者安装光盘目录Remote Debugger\x86下的文件rdbgsetup.exe,并拷贝到被调试机器里进行安装。

在目标机上执行命令:secpol.msc,进入本地安全设置画面,然后找到“本地策略-->安全选项-->网络访问:本地账户的共享和安全模式”,双击它并修改为“经典 - 本地用户以自己的身份验证”。

2、在目标机上启动Remote Debugger:开始-->程序-->Microsoft Visual Studio 2008-->Visual Studio Tools-->Visual Studio 2008 Remote Debugger。

3、在调试机上,起动vs2008,把项目编译成Debug版,然后把编译后的程序拷贝到目标机上。(主意要配置参数:Project Properties -> Configuration Properties -> C/C++, 'Debug Information Format' is set to 'Program Database/ Zi')

4、开始调试:vs2008菜单“Debug-->Attach to Process...”,在弹出的窗口里,Transport中选择Default,Qualifier中输入目标机的Ip地址或者主机名后回车。这时会列出目标机上进程。我选择explorer.exe进程,因为我要调试shell扩展程序,然后点击“Attach”按钮。此后可以设置断点,在目标机上起动程序,单步运行等进行调试了。

附录、Advance Installer:

安装Advance Installer安装包制作工具(从这里下载:http://www.onlinedown.net/soft/45832.htm),然后安装;

启动:开始-->所有程序-->工具-->安装工具-->Advance Installer-->Advance Installer,菜单“文件-->打开”,定位打开文件D:\vs2008\moodisk\zh_CN\SetupPackage\moodisk.aip,然后直接菜单“工程-->构建”,构建完了之后浏览安装包:菜单“工程-->打开输出文件夹”。

vs2008使用期限90天,到期就不能用了,此时很多人选择重新安装。更好的解决办法是升级为正式版本,这样就一劳永逸了。具体的升级步骤是:

进入控制面板的“添加/删除程序”,然后找到“Microsoft Visual Studio 2008 Professional Edition - ENU”,点击“更改/删除”按钮(放心,不是真的删除),然后点击“下一步”,最后在界面的左下角处输入序列号“XMQ2Y-4T3V6-XJ48Y-D3K2V-6C4WT”并点击“升级”按钮即可。

因为九十天试用版本已经是rtm版本。所以改变序列号以后的升级或者安装,就会变成正式版,不再有使用期限。
以下是收集的序列号:
1.Visual   Studio   2008   Professional   Edition:
XMQ2Y-4T3V6-XJ48Y-D3K2V-6C4WT

2.Visual   Studio   2008   Team   Test   Load   Agent:
WPX3J-BXC3W-BPYWP-PJ8CM-F7M8T

3.Visual   Studio   2008   Team   System:
PYHYP-WXB3B-B2CCM-V9DX9-VDY8T

4.Visual   Studio   2008   Team   Foundation   Server:
WPDW8-M962C-VJX9M-HQB4Q-JVTDM

今天,在盛大某网站注册的时候,身份证必填,但我又不想填真实身份证号码,于是随便编了串自认为合法的身份证号码,但是却马上被提示号码错误,由于响应速度极快,可以肯定不是联机校验正确性的,那也就是说第二代身份证除了大家都知道的几位表示生日和性别的规则以外,还有另外的自我校验规则。于是翻开页面源码查看,发现这段js没有被压缩,所以规则也很好懂。
就在这里给大家科普下,不知道是不是火星了,呵呵。
以下代码来自这里,版权归盛大。当然,你也可以在维基百科找到更详细的介绍和算法。

iW = new Array(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1);
iSum = 0;

for( i=0;i<17;i++){
    iC = v_card.charAt(i) ;
    iVal = parseInt(iC);
    iSum += iVal * iW[i];
}
iJYM = iSum % 11;
var sJYM = '';
if(iJYM == 0) sJYM = "1";
else if(iJYM == 1) sJYM = "0";
else if(iJYM == 2) sJYM = "x";
else if(iJYM == 3) sJYM = "9";
else if(iJYM == 4) sJYM = "8";
else if(iJYM == 5) sJYM = "7";
else if(iJYM == 6) sJYM = "6";
else if(iJYM == 7) sJYM = "5";
else if(iJYM == 8) sJYM = "4";
else if(iJYM == 9) sJYM = "3";
else if(iJYM == 10) sJYM = "2";
var cCheck = v_card.charAt(17).toLowerCase();
if( cCheck != sJYM ){
    return false; //对不上就是假号码
}

moodisk编写注意事项 2010年11月28日

1、在开发机器上要把项目目录下的文件zlib1.dll拷贝到c:\windows\system32下。否则注册moodiskExplorer.dll时出错。
2、修改文件altcom.h的第5032行为:
hr = Copy::copy(pelt, (CMoodiskFilePidl *)&*m_iter);
修改要清除项目临时文件,然后重新编译
3、从魔盘-->硬盘,执行路径:moodiskFileStream.h...72:Read()-->moodiskFile.h...71:Read()-->GenericFileSystem.h...88:Read()-->moodiskSFTPFileSystem.cpp...596:Read()-->...635:libssh2_sftp_read().
4、当一个dll没法注册的时候,往往是缺少以来的文件,这是可以查看到底缺少什么文件,用命令:
depends filename.dll
注意:windows xp默认是没有这个工具的,需要安装Windows XP Service Pack 2 Support Tools
5、杀死explorer.exe进程和重启它:
taskkill /f /im explorer.exe && explorer.exe
6、先结束explorer.exe进程,然后直接编译moodiskExplorer工程和重启explorer.exe进程,即可点击桌面上的Moodisk图标进行操作了。
7、先装Windows SDK v7.0,然后安装vs 2008,此后又重新安装了SDK v.70,如果安装位置不同,那么在vs2008中还是使用之前sdk的安装目录,尽管做了如下操作:
Microsoft Windows SDK v7.0-->Visual Studio Registration-->Windows SDK Configuration Tool: Make Current v7.0
这时手工修改vs2008中的设置了:vs2008-->Tool-->Options...-->Projects and Solutions-->VC++ Directries:
Executable Files,在这里修改$(WindowsSdkDir)/bin为sdk安装目录下的bin目录,如:D:\Program Files\Microsoft SDKs\Windows\v7.0\Bin
Include Files,在这里修改$(WindowsSdkDir)/include为sdk安装目录下的include,如:
D:\Program Files\Microsoft SDKs\Windows\v7.0\Include
8、编译成win7和vista的时候,需要修改头文件stdafx.h中的操作系统版本号:
#ifndef _WIN32_WINNT    // Allow use of features specific to Windows NT 4 or later.
//#define _WIN32_WINNT 0x0500    // Change this to the appropriate value to target Windows 2000 or later.
#define _WIN32_WINNT 0x0601    // Change this to the appropriate value to target Windows VISTA or later.
#endif
9、多语言支持:
1)搜寻CHINESE或者ENGLISH
2)编辑stdafx.h和translation.h两个头文件,并把项目根下的文件moodiskExplorer.rc内容全部替换项目moodiskexplorer下的相应文件
3)修改安装项目SetupProj的语言等。
10、把moodisk图标添加到右键菜单的“发送”中,在开始-->运行:shell:sendto,打开一个目录,在里面创建一个快捷方式指到桌面上的moodisk即可。
11、从snapshot上下载最新的libssh2-1.2.8存在bug,需要从git下载最新的:
git clone git://git.libssh2.org/libssh2.git
同步下来之后需要把1.2.8版本下的win32目录中的libssh2.dsp拷贝到相应目录。不过上传多个文件时还是存在bug,这一点与libssh2的低版本一样。
12、编译openssh-server的配置命令:
./configure --with-pid-dir=/var/run --with-superuser-path=/root --with-default-path=/usr/sbin:/usr/bin:/sbin:/bin  --with-selinux --with-pam --prefix=/usr  --sysconfdir=/etc/ssh --mandir=/tmp --docdir=/tmp

下面的例子演示了windows shell扩展编程的一般方法———获取目录c:\program files\下的对象,然后再列出改目录下的第一个子目录中的对象。

#include "stdafx.h"
#include <Shlobj.h>
#include <Shlwapi.h>
int _tmain(int argc, _TCHAR* argv[])
{
LPITEMIDLIST pidlProgFiles = NULL;
LPITEMIDLIST pidlItems = NULL;
IShellFolder *psfFirstFolder = NULL;
IShellFolder *psfDeskTop = NULL;
IShellFolder *psfProgFiles = NULL;
LPENUMIDLIST ppenum = NULL;
ULONG celtFetched;
HRESULT hr;
STRRET strDispName;
TCHAR pszDisplayName[MAX_PATH];
ULONG uAttr;
CoInitialize( NULL );
hr = SHGetFolderLocation(NULL, CSIDL_PROGRAM_FILES, NULL, NULL, &pidlProgFiles);
// hr = SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, NULL, &pidlProgFiles);
hr = SHGetDesktopFolder(&psfDeskTop);
hr = psfDeskTop->BindToObject(pidlProgFiles, NULL, IID_IShellFolder, (LPVOID *) &psfProgFiles);
psfDeskTop->Release();
hr = psfProgFiles->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);
while( hr = ppenum->Next(1,&pidlItems, &celtFetched) == S_OK && (celtFetched) == 1)
{
HRESULT ret = psfProgFiles->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &strDispName);
if(FAILED(ret))continue;
ret = StrRetToBuf(&strDispName, pidlItems, pszDisplayName, MAX_PATH);
if(FAILED(ret))continue;
MessageBox(NULL,pszDisplayName,_T("1111"),0);
wprintf(_T("%s\n"),pszDisplayName);
if(!psfFirstFolder)
{
uAttr = SFGAO_FOLDER;
psfProgFiles->GetAttributesOf(1, (LPCITEMIDLIST *) &pidlItems, &uAttr);
if(uAttr & SFGAO_FOLDER)
{
hr = psfProgFiles->BindToObject(pidlItems, NULL, IID_IShellFolder, (LPVOID *) &psfFirstFolder);
}
}
CoTaskMemFree(pidlItems);
}
ppenum->Release();
if(psfFirstFolder)
{
hr = psfFirstFolder->EnumObjects(NULL,SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &ppenum);
while( hr = ppenum->Next(1,&pidlItems, &celtFetched) == S_OK && (celtFetched) == 1)
{
psfFirstFolder->GetDisplayNameOf(pidlItems, SHGDN_INFOLDER, &strDispName);
StrRetToBuf(&strDispName, pidlItems, pszDisplayName, MAX_PATH);
wprintf(_T("%s\n"),pszDisplayName);
CoTaskMemFree(pidlItems);
}
}
ppenum->Release();
CoTaskMemFree(pidlProgFiles);
psfProgFiles->Release();
psfFirstFolder->Release();
CoUninitialize();
return 0;
}
在vs2008中配置SDK 7.0:
开始> 所有程序 > Microsoft Windows SDK v7.0 > Visual Studio Registration > Windows SDK Configuration Tool.
然后在下拉框选择 SDK v7

#define Nb 4

// xtime is a macro that finds the product of {02} and the argument to xtime modulo {1b}
#define xtime(x)   ((x<<1) ^ (((x>>7) & 1) * 0x1b))
// Multiplty is a macro used to multiply numbers in the field GF(2^8)
#define Multiply(x,y) (((y & 1) * x) ^ ((y>>1 & 1) * xtime(x)) ^ ((y>>2 & 1) * xtime(xtime(x))) ^ ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ ((y>>4 & 1) * xtime(xtime(xtime(xtime(x))))))

//The length of Key is 128 or 192 or 256,and Nk=length(Key)/32, Nr=Nk+6. Here the length is 128.
int Nk=4;
int Nr=10;
unsigned char RoundKey[240];
unsigned char Key[32];

int sbox[256] = {
//0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //A
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //B
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //C
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //D
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //E
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; //F

int rsbox[256] = {
//0     1    2      3     4    5     6     7      8    9     A      B    C     D     E     F
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d };

int Rcon[255] = {
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39,
0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a,
0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef,
0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc,
0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b,
0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3,
0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94,
0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35,
0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f,
0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04,
0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63,
0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd,
0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb  };

//Notice: the length of the variables 'in' and 'out' is not great than 16.
int aes_encrypt(const unsigned char *in, unsigned char *out, const unsigned char *key)
{
int i,j,round=0;
unsigned char temp[4]={10,13,100,0},k;
unsigned char state[4][4];

// Expand the key:
strcpy(RoundKey,key);
strcat(RoundKey,temp);
i=strlen(RoundKey)/4;

while (i < (Nb * (Nr+1)))
{
for(j=0;j<4;j++)
{
temp[j]=RoundKey[(i-1) * 4 + j];
}
if (i % Nk == 0)
{
// This function rotates the 4 bytes in a word to the left once.
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]

// Function RotWord()
{
k = temp[0];
temp[0] = temp[1];
temp[1] = temp[2];
temp[2] = temp[3];
temp[3] = k;
}

// SubWord() is a function that takes a four-byte input word and
// applies the S-box to each of the four bytes to produce an output word.

// Function Subword()
{
temp[0]=sbox[temp[0]];
temp[1]=sbox[temp[1]];
temp[2]=sbox[temp[2]];
temp[3]=sbox[temp[3]];
}

temp[0] =  temp[0] ^ Rcon[i/Nk];
}
else if (Nk > 6 && i % Nk == 4)
{
// Function Subword()
{
temp[0]=sbox[temp[0]];
temp[1]=sbox[temp[1]];
temp[2]=sbox[temp[2]];
temp[3]=sbox[temp[3]];
}
}
RoundKey[i*4+0] = RoundKey[(i-Nk)*4+0] ^ temp[0];
RoundKey[i*4+1] = RoundKey[(i-Nk)*4+1] ^ temp[1];
RoundKey[i*4+2] = RoundKey[(i-Nk)*4+2] ^ temp[2];
RoundKey[i*4+3] = RoundKey[(i-Nk)*4+3] ^ temp[3];
i++;
}

for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] = in[i*4 + j];
}
}

// Add the First round key to the state before starting the rounds.
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] ^= RoundKey[round * Nb * 4 + i * Nb + j];
}
}

// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr-1 rounds are executed in the loop below.
for(round=1;round<Nr;round++)
{
//SubBytes:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[i][j] = sbox[state[i][j]];

}
}

//ShiftRows
k=state[1][0];
state[1][0]=state[1][1];
state[1][1]=state[1][2];
state[1][2]=state[1][3];
state[1][3]=k;

k=state[2][0];
state[2][0]=state[2][2];
state[2][2]=k;

k=state[2][1];
state[2][1]=state[2][3];
state[2][3]=k;

k=state[3][0];
state[3][0]=state[3][3];
state[3][3]=state[3][2];
state[3][2]=state[3][1];
state[3][1]=k;

//MixColumns:
for(i=0;i<4;i++)
{
k=state[0][i];
temp[0] = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i] ;
temp[1] = state[0][i] ^ state[1][i] ; temp[1] = xtime(temp[1]); state[0][i] ^= temp[1] ^ temp[0] ;
temp[1] = state[1][i] ^ state[2][i] ; temp[1] = xtime(temp[1]); state[1][i] ^= temp[1] ^ temp[0] ;
temp[1] = state[2][i] ^ state[3][i] ; temp[1] = xtime(temp[1]); state[2][i] ^= temp[1] ^ temp[0] ;
temp[1] = state[3][i] ^ k ; temp[1] = xtime(temp[1]); state[3][i] ^= temp[1] ^ temp[0] ;
}

//AddRoundKey:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] ^= RoundKey[round * Nb * 4 + i * Nb + j];
}
}
}

// The last round is given below.
// The MixColumns function is not here in the last round.
//SubBytes:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[i][j] = sbox[state[i][j]];

}
}

//ShiftRows
k=state[1][0];
state[1][0]=state[1][1];
state[1][1]=state[1][2];
state[1][2]=state[1][3];
state[1][3]=k;

k=state[2][0];
state[2][0]=state[2][2];
state[2][2]=k;

k=state[2][1];
state[2][1]=state[2][3];
state[2][3]=k;

k=state[3][0];
state[3][0]=state[3][3];
state[3][3]=state[3][2];
state[3][2]=state[3][1];
state[3][1]=k;

//AddRoundKey:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] ^= RoundKey[Nr * Nb * 4 + i * Nb + j];
}
}

// The encryption process is over.
// Copy the state array to output array.
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
out[i*4+j]=state[j][i];
}
}
}

//Notice: the length of the variables 'in' and 'out' is not great than 16.
int aes_decrypt(const unsigned char *in, unsigned char *out, const unsigned char *key)
{
int i,j,round=0;
unsigned char temp[5]={10,13,100,113,0},k;
unsigned char state[4][4];

// Expand the key:
strcpy(RoundKey,key);
strcat(RoundKey,temp);
i=strlen(RoundKey)/4;

while (i < (Nb * (Nr+1)))
{
for(j=0;j<4;j++)
{
temp[j]=RoundKey[(i-1) * 4 + j];
}
if (i % Nk == 0)
{
// This function rotates the 4 bytes in a word to the left once.
// [a2,a1,a2,a3] becomes [a1,a2,a3,a0]

// Function RotWord()
{
k = temp[0];
temp[0] = temp[1];
temp[1] = temp[2];
temp[2] = temp[3];
temp[3] = k;
}

// SubWord() is a function that takes a four-byte input word and
// applies the S-box to each of the four bytes to produce an output word.

// Function Subword()
{
temp[0]=sbox[temp[0]];
temp[1]=sbox[temp[1]];
temp[2]=sbox[temp[2]];
temp[3]=sbox[temp[3]];
}

temp[0] =  temp[0] ^ Rcon[i/Nk];
}
else if (Nk > 6 && i % Nk == 4)
{
// Function Subword()
{
temp[0]=sbox[temp[0]];
temp[1]=sbox[temp[1]];
temp[2]=sbox[temp[2]];
temp[3]=sbox[temp[3]];
}
}
RoundKey[i*4+0] = RoundKey[(i-Nk)*4+0] ^ temp[0];
RoundKey[i*4+1] = RoundKey[(i-Nk)*4+1] ^ temp[1];
RoundKey[i*4+2] = RoundKey[(i-Nk)*4+2] ^ temp[2];
RoundKey[i*4+3] = RoundKey[(i-Nk)*4+3] ^ temp[3];
i++;
}

for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] = in[i*4 + j];
}
}

// Add the First round key to the state before starting the rounds.
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] ^= RoundKey[round * Nb * 4 + i * Nb + j];
}
}

// There will be Nr rounds.
// The first Nr-1 rounds are identical.
// These Nr-1 rounds are executed in the loop below.
for(round=Nr-1;round>0;round--)
{
//1.InvShiftRows:
k=state[1][3];
state[1][3]=state[1][2];
state[1][2]=state[1][1];
state[1][1]=state[1][0];
state[1][0]=k;

k=state[2][0];
state[2][0]=state[2][2];
state[2][2]=k;

k=state[2][1];
state[2][1]=state[2][3];
state[2][3]=k;

k=state[3][0];
state[3][0]=state[3][1];
state[3][1]=state[3][2];
state[3][2]=state[3][3];
state[3][3]=k;

//2.InvSubBytes:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[i][j] = rsbox[state[i][j]];
}
}

//3.AddRoundKey:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] ^= RoundKey[round * Nb * 4 + i * Nb + j];
}
}

//4.InvMixColumns:
for(i=0;i<4;i++)
{

temp[0] = state[0][i];
temp[1] = state[1][i];
temp[2] = state[2][i];
temp[3] = state[3][i];

state[0][i] = Multiply(temp[0], 0x0e) ^ Multiply(temp[1], 0x0b) ^ Multiply(temp[2], 0x0d) ^ Multiply(temp[3], 0x09);
state[1][i] = Multiply(temp[0], 0x09) ^ Multiply(temp[1], 0x0e) ^ Multiply(temp[2], 0x0b) ^ Multiply(temp[3], 0x0d);
state[2][i] = Multiply(temp[0], 0x0d) ^ Multiply(temp[1], 0x09) ^ Multiply(temp[2], 0x0e) ^ Multiply(temp[3], 0x0b);
state[3][i] = Multiply(temp[0], 0x0b) ^ Multiply(temp[1], 0x0d) ^ Multiply(temp[2], 0x09) ^ Multiply(temp[3], 0x0e);
}
}

//InvShiftRows:
k=state[1][3];
state[1][3]=state[1][2];
state[1][2]=state[1][1];
state[1][1]=state[1][0];
state[1][0]=k;

k=state[2][0];
state[2][0]=state[2][2];
state[2][2]=k;

k=state[2][1];
state[2][1]=state[2][3];
state[2][3]=k;

k=state[3][0];
state[3][0]=state[3][1];
state[3][1]=state[3][2];
state[3][2]=state[3][3];
state[3][3]=k;

//InvSubBytes:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[i][j] = rsbox[state[i][j]];
}
}

//AddRoundKey:
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
state[j][i] ^= RoundKey[0 * Nb * 4 + i * Nb + j];
}
}

// The decryption process is over.
// Copy the state array to output array.
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
out[i*4+j]=state[j][i];
}
}
}

void main()
{
int i;

unsigned char temp[17] = {0x0a  ,0x01  ,0x02  ,0x03  ,0x04  ,0x05  ,0x06  ,0x07  ,0x08  ,0x09  ,0x0a  ,0x0b  ,0x0c  ,0x0d  ,0x0e  ,0x0f,0x00};
unsigned char temp2[16]= {0x00  ,0x11  ,0x22  ,0x33  ,0x44  ,0x55  ,0x66  ,0x77  ,0x88  ,0x99  ,0xaa  ,0xbb  ,0xcc  ,0xdd  ,0xee  ,0xff};
unsigned char temp3[16]= {0xb0,0xdc,0x5f,0x65,0xa4,0xf0,0x09,0xcb,0xaf,0xac,0x71,0xb9,0x7b,0x80,0x82,0x04};

unsigned char out[16];
aes_encrypt(temp2,out,temp);
// Output the encrypted text.
printf("\nText after encryption:\n");
for(i=0;i<Nk*4;i++)
printf("%02x ",out[i]);
printf("\n\n");

aes_decrypt(temp3,out,temp);
// Output the decrypted text.
printf("\nText after decryption:\n");
for(i=0;i<Nk*4;i++)
printf("%02x ",temp2[i]);
printf("\n\n");
}


开发平台:ActivePerl + OpenSSL + Zlib + Libssh2 + Visual Studio 2008
SSH2是一套安全通讯协议框架(早期的SSH1由于存在安全漏洞,现在已经不用了),基于SSH2协议的产品目前主要有openssh(http://www.openssh.org/),putty(http://www.putty.org/),SSH Secure Shell Client(从http://www.moodisk.com/zh_CN/index.html?src=download.php可以下载)等,这些都是开源的,但是这些代码非常难懂而且复杂,一个个函数深层次的调用很快就让人在C语言代码的海洋中迷失了方向,妄图通过从这些开源软件中抽取程序代码段来“组装”自己的应用程序是非一般人所能实现的。不过还好网路上出现了一些开源的SSH2开发库,利用这些开发库开发自己的SSH2程序却要简单得多,由于这些开发库都是开源的,往往是针对linux平台的,而且一般只提供了源代码。在windows上利用这些库还必须要完成:编译有关依赖库-->编译ssh2库-->集成到开发环境(如Visual Studio)中-->熟悉SSH2库函数用法-->开始编写自己的程序。由于开发基于ssh2协议的例子网上很少,中文资料就更少。本人在完成这么一个开发环境就断断续续耗费了我一周的时间,现在终于可以开始编写的基于SSH2协议的程序了。我不敢独享,整理出一篇博文,和各位IT同仁分享。
本文的内容安排是:首先介绍如何编译各种依赖库,然后介绍如何把这些依赖库继集成到Visual Studio 2008中,接下来介绍基于SSH2协议的程序的一般框架,最后举一个实际的开发例子。附录A是我自己开发的一个实际例子,附录B列出了全部的libssh2库函数。

一·准备一些工具

1、安装Visual Studio 2008开发环境(最好是英文版的,我的是VS2008版本是9.0.30729.1 SP, Windows SDK 6.1)。什么?你不会装!你去google上搜一下“Visual Studio 2008安装过程详解”或者点击参考文章:http://dev.yesky.com/msdn/329/7823829.shtml
2、安装最新的MSDN文档库(可选,不装也行)。蛮大的,从网上下载要一些时间,或者参考在线文档http://msdn.microsoft.com/en-us/library/default.aspx
3、安装解压缩工具winRAR。从http://cncspace.newhua.com/down/files/wrar380sc.exe下载并安装。
4、安装汇编工具nasm。从http://www.nasm.us/pub/nasm/releasebuilds/2.06/win32/nasm-2.06-installer.exe下载并安装。
5、安装脚本语言ActivePerl。从http://downloads.activestate.com/ActivePerl/Windows/5.10/ActivePerl-5.10.0.1005-MSWin32-x86-290470.msi下载,然后安装(安装过程中选择默认选项即可)。

二、编译各种依赖库

LibSSH2库依赖openssl和zlib两个库,所以我们必须先编译zlib和openssl两个库。
1、zlib库。网上提供了源码和目标DLL安装包,我们直接下载DLL安装比较快捷,从http://www.zlib.net/zlib123-dll.zip下载,并解压到C:\zlib下(最终存在目录C:\zlib\include即表示正确),把C:\zlib\zlib1.dll拷贝到c:\windows\system32下。
2、OpenSSL库。OpenSSL库网上只有源代码,我们首先必须编译。从http://www.openssl.org/source/openssl-0.9.8k.tar.gz下载源代码包,然后解压到目录C:\openssl-0.9.8k下(最终存在目录C:\openssl-0.9.8k\apps即表示正确)。进入Visual Studio 2008的命令提示符(开始-->所有程序-->Microsoft Visual Studio 2008-->Visual Studio Tools-->Visual Studio 2008 Command Prompt),依次输入如下命令:
mkdir c:\openssl_lib
cd C:\openssl-0.9.8k
perl Configure VC-WIN32 --prefix=c:/openssl_lib
---输出如下的信息:
……
RC4_CHUNK is undefined
Configured for VC-WIN32.
ms\do_masm
nmake -f ms\nt.mak
---好了,去喝杯咖啡吧,半个小时后应该编译完了。
nmake -f ms/nt.mak test
---如何库编译正确,你应该看到“passwd all tests”字样。
nmake -f ms\nt.mak install
---现在应该在c:\openssl_lib下安装了openssl库文件和头文件了。
---如果编译出错,那么也可以查看文件C:\openssl-0.9.8k\INSTALL.W32,里面列举了一些错误处理方法。
3、LibSSH2库。LibSSH2库网上只有源代码,我们首先必须编译。从http://nchc.dl.sourceforge.net/sourceforge/libssh2/libssh2-1.1.tar.gz下载源代码包,然后解压到目录C:\libssh2-1.1下(存在目录C:\libssh2-1.1\include表示正确),创建目录“C:\libssh2\lib”和“C:\libssh2\include”,在Visual Studio 2008 IDE中打开C:\libssh2-1.1\win32\libssh2.dsw,编辑文件libssh2.h,把如下的第54行
# define LIBSSH2_API __declspec(dllexport)
替换成:
# define LIBSSH2_API// __declspec(dllexport)
在左边的Solution Explorer中右击libssh2_lib-->Properties-->Configuration Properties:
-->C/C++ --> General -->选择Additional Include Dirextories-->附加
;C:\openssl_lib\include;C:\zlib\include
-->Code Generation --> Runtime Library -->选择Multi-thread(/MT)
-->Librarian --> General:
Output File --> C:\libssh2\lib\libssh2.lib
Additional Dependencies --> libeay32.lib ssleay32.lib zdll.lib
Additional Library Directories --> 附加路径C:\openssl_lib\lib;C:\zlib\lib
最后点击“OK"确定。
现在可以开始编译了,右击libssh2_lib选择Build。如果编译成功那么在C:\libssh2\lib下存在文件libssh2.lib了。接下来再把C:\libssh2-1.1\include下的全部文件拷贝到C:\libssh2\include下,把文件C:\libssh2-1.1\win32\libssh2_config.h也拷贝到C:\libssh2\include下。好了,那么我们最终编译的库和头文件布局如下:
C:\libssh2\include下有文件:libssh2.h,libssh2_config.h,libssh2_publickey.h,libssh2_sftp.h;
C:\libssh2\lib下有文件libssh2.lib
--- 如果编译失败,你可以从这里直接下载我编译好的LibSSH2库。

三·一个实例

windwos平台上基于SSH2协议的程序框架是:
初始化Winsock动态库(WSAStartup())
|
V
创建标准的socket套接字并连接(socket(),connect())
|
V
创建和启用一个SSH2会话(libssh2_session_init(),libssh2_session_startup())
|
V
获取指纹数据(libssh2_hostkey_hash())
|
V
认证(libssh2_userauth_password()或libssh2_userauth_publickey_fromfile())
|
V
初始化sftp子系统(libssh2_sftp_init())
|
V
进行各种sftp操作命令(如创建目录、下载等,函数参见本文附录B)
|
V
关闭sftp子系统(libssh2_sftp_shutdown())
|
V
拆除ssh2会话(libssh2_session_disconnect())
|
V
释放ssh2会话结构(libssh2_session_free())
|
V
关闭标准socket套接字(closesocket())
注意:上面列出的函数的具体用法请参阅网站在线文档:http://www.libssh2.org/wiki/index.php/Documentation
下面用一个具体的实例进一步说明如何开发一个ssh2世纪功能,它实现一个简单的功能:在服务器上创建一个目录,列出另外一个目录下的文件。本实例主要展示SSH2协议的程序框架。
1、在Visual Studio 2008开发环境中新建一个工程: File-->New-->Project...-->展开Visual C++ --> 选择Win32 Console Application,Name处输入testsftp,Location处出入C:\projects,Solution Name处输入testftp,勾选Create directory for solution,最后点击OK进入下一步再点击Next。这一页只点选Console application,其他项都不要勾选或点选。最后点击Finish按钮完成新工程的创建。
2、在左边的工程浏览器窗口中展开Source Files,双击“testsftp.cpp”文件打开,里面只有寥寥数行:
// newsftp.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
return 0;
}
3、在屏幕左边的Solution Explorer中右击工程testsftp-->Properties-->Configuration Properties:
-->C/C++ --> General -->选择Additional Include Dirextories-->加C:\libssh2\include
--> Code Generation -->Runtime Library -->选择Multi-thread(/MT)
-->Linker
--> General -->选择Additional Library Directories --> 加C:\libssh2\lib
--> Input -->选择Additional Dependencies --> 加libssh2.lib
--> Command Line -->在Additional options中加 Ws2_32.lib
最后点击“OK"确定。
4、开始编译。按F7或点击菜单Build-->Build Solution。
不过我后来发现利用libssh2开发的程序存在一个严重的问题:总是在sftp_write()函数中被挂起,导致文件上传停顿。经过一段时间的艰苦测试,发现采用非阻塞模式时不存在这个问题。

附录A:我的testsftp.cpp文件内容

// testsftp.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <libssh2_config.h>
#include <io.h>
#include <libssh2.h>
#include <libssh2_sftp.h>
#ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
# ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
int _tmain(int argc, char* argv[])
{
int sock, i, auth_pw = 1;
struct sockaddr_in sin;
const char *fingerprint;
LIBSSH2_SESSION *session;
int rc;
LIBSSH2_SFTP *sftp_session;
LIBSSH2_SFTP_HANDLE *sftp_handle;
#ifdef WIN32
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0), &wsadata);
#endif
/*
* The application code is responsible for creating the socket
* and establishing the connection
*/
if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))==INVALID_SOCKET){
fprintf(stderr,"failed to create a socket!\n");
return -1;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(22);
if((sin.sin_addr.s_addr = inet_addr("192.168.104.105"))==INADDR_NONE){
fprintf(stderr,"The address is invalid!\n");
return -1;
}
if(connect(sock, (struct sockaddr*)(&sin),sizeof(struct sockaddr_in))!= 0){
fprintf(stderr, "failed to connect!\n");
return -1;
}
/* Create a session instance*/
if(!(session = libssh2_session_init())){
fprintf(stderr,"Init SSH session failed!\n");
goto CLOSESOCKET;
}
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
if((rc = libssh2_session_startup(session, sock))){
fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
libssh2_session_free(session);
goto CLOSESOCKET;
}
/* At this point we havn't yet authenticated.  The first thing to do
* is check the hostkey's fingerprint against our known hosts Your app
* may have it hard coded, may go to a file, may present it to the
* user, that's your call
*/
if((fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5))){
printf("Fingerprint: ");
for(i = 0; i < 16; i++) {
printf("%02X ", (unsigned char)fingerprint[i]);
}
printf("\n");
}
if (auth_pw) {
/* We could authenticate via password */
if ((libssh2_userauth_password(session, "sftpuser", "abc123"))) {
printf("Authentication by password failed.\n");
goto SHUTDOWN;
}
} else {
/* Or by public key */
if (libssh2_userauth_publickey_fromfile(session, "sftpuser","/home/username/.ssh/id_rsa.pub","/home/username/.ssh/id_rsa","abc123")) {
printf("\tAuthentication by public key failed\n");
goto SHUTDOWN;
}
}
fprintf(stderr, "libssh2_sftp_init()!\n");
if(!(sftp_session = libssh2_sftp_init(session))){
fprintf(stderr, "Unable to init SFTP session\n");
goto SHUTDOWN;
}
/* Since we have not set non-blocking, tell libssh2 we are blocking */
libssh2_session_set_blocking(session, 1);
fprintf(stderr, "libssh2_sftp_opendir()!\n");
//建目录
if(libssh2_sftp_mkdir(sftp_session, "sftpdir/cba",
LIBSSH2_SFTP_S_IRWXU|
LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IXGRP|
LIBSSH2_SFTP_S_IROTH|LIBSSH2_SFTP_S_IXOTH)==-1)
fprintf(stderr,"Create dir failed!\n");
//浏览一个目录中的文件
if(!(sftp_handle = libssh2_sftp_opendir(sftp_session, "sftpdir"))){
fprintf(stderr, "Unable to open dir with SFTP\n");
goto SHUTDOWN;
}
fprintf(stderr, "libssh2_sftp_opendir() is done, now receive listing!\n");
do {
char mem[512];
char longentry[512];
LIBSSH2_SFTP_ATTRIBUTES attrs;
/* loop until we fail */
rc = libssh2_sftp_readdir_ex(sftp_handle, mem, sizeof(mem), longentry, sizeof(longentry), &attrs);
if(rc > 0) {
/* rc is the length of the file name in the membuffer */
if (longentry[0] != '\0') {
printf("%s\n", longentry);
} else {
if(attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
/* this should check what permissions it is and print the output accordingly */
printf("--fix----- ");
}else {
printf("---------- ");
}
if(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) {
printf("%4ld %4ld ", attrs.uid, attrs.gid);
}else {
printf("   -    - ");
}
if(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
/* attrs.filesize is an uint64_t according to the docs but there is no really good and portable 64bit type for C before C99, and correspondingly there was no good printf() option for it... */
printf("%8lld ", attrs.filesize);
}
printf("%s\n", mem);
}
}else break;
} while (1);
libssh2_sftp_closedir(sftp_handle);
libssh2_sftp_shutdown(sftp_session);
SHUTDOWN:
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing");
libssh2_session_free(session);
CLOSESOCKET:
#ifdef WIN32
Sleep(1000);
closesocket(sock);
#else
sleep(1);
close(sock);
#endif
printf("all done\n");
return 0;
}

附录B:libssh2.lib中函数列表

1. Session API:
libssh2_session_init()
libssh2_session_abstract()
libssh2_session_callback_set()
libssh2_banner_set()
libssh2_session_startup()
libssh2_session_disconnect()
libssh2_session_free()
libssh2_hostkey_hash()
libssh2_session_method_pref()
libssh2_session_methods()
libssh2_session_last_error()
libssh2_session_flag()
2. Userauth API:
libssh2_userauth_list()
libssh2_userauth_authenticated()
libssh2_userauth_password()
libssh2_userauth_publickey_fromfile()
libssh2_userauth_hostbased_fromfile()
libssh2_userauth_keyboard_interactive()
3. Channel API:
Channel Creation and Setup
libssh2_channel_open_session()
libssh2_channel_direct_tcpip()
libssh2_channel_forward_listen()
libssh2_channel_forward_cancel()
libssh2_channel_forward_accept()
libssh2_channel_setenv()
libssh2_channel_request_pty()
libssh2_channel_process_startup()
libssh2_channel_x11_req()
libssh2_scp_recv()
libssh2_scp_send()
Channel Shutdown and Destruction
libssh2_channel_send_eof()
libssh2_channel_eof()
libssh2_channel_close()
libssh2_channel_wait_closed()
libssh2_channel_get_exit_status()
libssh2_channel_free()
Input/Output
libssh2_channel_set_blocking()
libssh2_channel_read()
libssh2_channel_write()
libssh2_channel_handle_extended_data()
libssh2_channel_flush()
libssh2_poll_channel_read()
libssh2_poll()
Windowing
libssh2_channel_window_read()
libssh2_channel_receive_window_adjust()
libssh2_channel_window_write()
4. SFTP Subsystem:
Protocol startup and shutdown
libssh2_sftp_init()
libssh2_sftp_shutdown()
libssh2_sftp_last_error()
File/Directory Access
libssh2_sftp_open()
libssh2_sftp_opendir()
libssh2_sftp_read()
libssh2_sftp_readdir()
libssh2_sftp_write()
libssh2_sftp_close()
libssh2_sftp_closedir()
libssh2_sftp_seek()
libssh2_sftp_rewind()
libssh2_sftp_tell()
libssh2_sftp_fstat()
libssh2_sftp_fsetstat()
File/Directory Manipulation
libssh2_sftp_rename()
libssh2_sftp_unlink()
libssh2_sftp_mkdir()
libssh2_sftp_rmdir()
libssh2_sftp_stat()
libssh2_sftp_lstat()
libssh2_sftp_setstat()
libssh2_sftp_symlink()
libssh2_sftp_readlink()
libssh2_sftp_realpath()
5. Publickey Subsystem:
libssh2_publickey_init()
libssh2_publickey_shutdown()
libssh2_publickey_add()
libssh2_publickey_remove()
libssh2_publickey_list_fetch()
libssh2_publickey_list_free()

参考文献:

1. Using libcurl with SSH support in Visual Studio 2008.pdf(点击这里下载)
2. http://www.libssh2.org/wiki/index.php/Documentation