C++编程:XAudio2 API应用示例

C++编程:XAudio2 API应用示例

XAudio2是一个跨平台的API,在Xbox 360及Windows中得到支持。在Xbox 360上, XAudio2作为一个静态库编译到游戏可执行文件中。在Windows上,XAudio2提供一个动态链接库(DLL)。以下例子只使用了其中的一部分功能,并不全面。详情请看微软技术页的XAudio2编程相关(英文)。

使用XAudio2来播放未压缩的PCM音频数据的过程并不复杂,主要有以下几个步骤:

  1. 建立XAudio2 引擎

使用XAudio2Create函数,该函数的功能是创建一个XAudio2对象(IXAudio2接口)。

原型:HRESULT XAudio2Create(

IXAudio2 **ppXAudio2,//这里返回XAudio2对象的指针

UINT32 Flags,//此处必须为0

XAUDIO2_PROCESSOR XAudio2Processor//指定所用CPU,默认:XAUDIO2_DEFAULT_PROCESSOR

);

示例:XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR );

  1. 使用第1步建立的引擎建立MasteringVoice

使用IXAudio2成员函数CreateMasteringVoice,该函数功能是创建并设置一个MasteringVoice

原型:HRESULT CreateMasteringVoice(

IXAudio2MasteringVoice **ppMasteringVoice,//这里返回MasteringVoice对象指针

UINT32 InputChannels = XAUDIO2_DEFAULT_CHANNELS,//设置声道数,可选

UINT32 InputSampleRate = XAUDIO2_DEFAULT_SAMPLERATE, //设置采样率,可选

UINT32 Flags = 0,//必须是0,可选

LPCWSTR szDeviceId = NULL, //设备,可选,NULL代表全局默认输出设备

const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL, //音效,可选

AUDIO_STREAM_CATEGORY StreamCategory = AudioCategory_GameEffects//流类型,可选

);

示例:pXAudio2->CreateMasteringVoice(&pMasterVoice);

  1. 使用第一步建立的引擎建立SourceVoice(或SubmixVoice,以下按SourceVoice举例)

使用IXAudio2成员函数CreateSourceVoice,该函数功能是创建并设置一个SourceVoice

原型:HRESULT CreateSourceVoice(

IXAudio2SourceVoice **ppSourceVoice, //这里返回IXAudio2SourceVoice对象指针

const WAVEFORMATEX *pSourceFormat, //PCM音频格式(下面讲到)

UINT32 Flags = 0,//SourceVoide工作方式,可选

float MaxFrequencyRatio = XAUDIO2_DEFAULT_FREQ_RATIO,//声调,可选,默认为1

IXAudio2VoiceCallback *pCallback = NULL,//回调类指针,可选

const XAUDIO2_VOICE_SENDS *pSendList = NULL,//目标格式设置,可选

const XAUDIO2_EFFECT_CHAIN *pEffectChain = NULL//音效设置,可选

);

示例:pXAudio2->CreateSourceVoice(&pSourceVoice,&format,0,XAUDIO2_DEFAULT_FREQ_RATIO,NULL,NULL,NULL);

其中format这样设置:(位数为bits,声道数为channels,采样率为hz)

WAVEFORMATEX format;

format.wFormatTag = WAVE_FORMAT_PCM;//PCM格式

format.wBitsPerSample = bits;//位数

format.nChannels = channels;//声道数

format.nSamplesPerSec = hz;//采样率

format.nBlockAlign = bits*channels/8;//数据块调整

format.nAvgBytesPerSec = format.nBlockAlign*hz;//平均传输速率

format.cbSize = 0;//附加信息

  1. 呈交音频数据

使用IXAudio2SourceVoice的成员函数SubmitSourceBuffer,该函数功能是呈交一个XAUDIO2_BUFFER

原型:HRESULT SubmitSourceBuffer(

const XAUDIO2_BUFFER *pBuffer,// 结构体XAUDIO2_BUFFER的指针(下面讲到)

const XAUDIO2_BUFFER_WMA *pBufferWMA = NULL//wma格式Buffer的指针,可选,默认NULL

);

示例:pSourceVoice->SubmitSourceBuffer(&XAudio2Buffer,NULL);

其中XAudio2Buffer这样设置:

XAUDIO2_BUFFER XAudio2Buffer;

XAudio2Buffer.Flags = 0;//可以设为0或XAUDIO2_END_OF_STREAM,当设为后者时,将使XAudio2播放完该数据块后自动停止,不再播放下一个数据块

XAudio2Buffer.AudioBytes = BufferSize;// 音频数据的长度,按字节算

XAudio2Buffer.pAudioData = pBuffer;//具体音频数据的地址,unsigned char pBuffer[]

XAudio2Buffer.PlayBegin = 0;//起始播放地址

XAudio2Buffer.PlayLength = 0;//播放长度,0为整数据块

XAudio2Buffer.LoopBegin = 0;//循环起始位置

XAudio2Buffer.LoopLength = 0;//循环长度,按字节算

XAudio2Buffer.LoopCount = 0;//循环次数,0为不循环,255为无限循环

XAudio2Buffer.pContext = NULL;//这里的pContext用来标识该数据块,供回调用,可以是NULL

  1. 继续呈交数据和播放数据:

播放呈交的数据使用IXAudio2SourceVoice的成员函数Start,该函数功能是开始播放。

原型:HRESULT Start(

UINT32 Flags,//必须是0

UINT32 OperationSet = XAUDIO2_COMMIT_NOW//使用XAUDIO2_COMMIT_NOW将立即生效,使用XAUDIO2_COMMIT_ALL将挂起,等待其它的数值的OperationSet的处理完

);

示例:pSourceVoice->Start(0, XAUDIO2_COMMIT_NOW);

第5步做完之后,XAudio2将一块接一块地播放呈交的数据块。我们只需不断重复第四步,就能不断地播放音频数据了。需要注意的是,在XAudio2播放完某个XAudio2Buffer之前,该XAudio2Buffer以及XAudio2Buffer.pAudioData所指向的内存不能被修改或删除,否则将发生错误。但是某个XAudio2Buffer一旦被播放完,就能被修改了。为此,我们可以创建一个数组XAUDIO2_BUFFER []来循环呈交和更新数据。那怎么知道XAudio2到底播放了几个XAudio2Buffer呢,可以使用IXAudio2SourceVoice的成员函数GetState

原型:GetState(

XAUDIO2_VOICE_STATE *pVoiceState,// 这里返回XAUDIO2_VOICE_STATE结构体指针

[optional]  UINT32 Flags//获取方式,可选,默认0.设为XAUDIO2_VOICE_NOSAMPLESPLAYED将只获取挂起(包括正在播放)的XAudio2Buffer数量,速度较快。注意:DirectX SDK版本没有此参数

);

XAUDIO2_VOICE_STATE包含三个成员:

void * pCurrentBufferContext//对应XAUDIO2_BUFFER中的pContext

UINT32 BuffersQueued//挂起(包括正在播放)的XAudio2Buffer数量

UINT64 SamplesPlayed//已播放的样本数

示例: pSourceVoice->GetState(&state);

  1. 暂停和停止播放

暂停播放使用IXAudio2SourceVoice的成员函数:Stop

原型:HRESULT Stop(

UINT32 Flags,// 设为0或XAUDIO2_PLAY_TAILS,后者代表等待音效放完

UINT32 OperationSet = XAUDIO2_COMMIT_NOW// XAUDIO2_COMMIT_NOW立即生效

);

如果设定XAUDIO2_PLAY_TAILS,应在音效输出完成后设定0,再Stop一次。

暂停后再次调用Start将在暂停的位置开始播放。

如果要完全停止,还需要使用IXAudio2SourceVoice的成员函数FlushSourceBuffers,该函数功能是清除挂起的XAudio2Buffer队列。

原型:HRESULT FlushSourceBuffers();

说明:该函数使用后要到XAudio2播放完一个XAudio2Buffer才生效,建议在回调中使用。使用该函数后,XAudio2Buffer队列计数将置0

  1. IXAudio2SourceVoice的其他功能:设置声调使用SetFrequencyRatio函数

原型:HRESULT SetFrequencyRatio(

float Ratio,//1.0为正常声调,>1.0为高声调快放,<1.0为低声调慢放

UINT32 OperationSet = XAUDIO2_COMMIT_NOW

);

IXAudio2SourceVoice继承自IXAudio2Voice,所以还有许多IXAudio2Voice的功能,比如设置音量用SetVolume等。

注意:以上IXAudio2SourceVoice的成员函数中, Stop、GetState、 FlushSourceBuffers可以在回调中使用

释放相关实例的顺序与创建他们的顺序相反。需要包含头文件Xaudio2.h和Objbase.h以及链接ole32.lib(而不是Microsoft网站上的Xaudio2.lib)

下面给出我写的一个Speaker类供大家参考,该类使用XAudio2来播放PCM数据,在Win7x64系统中使用VS2010、DirectX SDK按x64、/clr(Speaker中没有使用托管类)编译测试通过

其公开成员函数ReadData采用阻塞的方法来读取音频数据,一旦塞满缓冲区将自动开始播放,播放多少就读取多少,SetFormat设置PCM音频格式(不设置的话,默认是16位、2声道、44100采样率)。SetBufferSize设置缓冲块数和每块大小(不设置的话,默认是4块,每块40KB)

#include <Windows.h>

#include <xaudio2.h>

#include "Objbase.h"

#pragma comment(lib,"Ole32.lib")

#define DEF_MaxBufferCount4

#define DEF_StreamingBufferSize40960

class VoiceCallBack;

class Speaker;

class VoiceCallBack:public IXAudio2VoiceCallback

{//回调类

public:HANDLE hBufferEndEvent;

VoiceCallBack():hBufferEndEvent(CreateEvent(NULL,FALSE,FALSE,NULL))

{count =lastcontext = currentcontext= 0; }

~VoiceCallBack(){CloseHandle(hBufferEndEvent);}

Speaker *speaker;

XAUDIO2_VOICE_STATE state;

public:int count;

int lastcontext;

int currentcontext;

//播放一个数据块前后触发事件

void OnBufferEnd(void *pBufferContext);

//不需要的方法只保留声明

void OnBufferStart(void *pBufferContext){}

void OnVoiceProcessingPassEnd(){}

void OnVoiceProcessingPassStart(UINT32 SamplesRequired){}

void OnStreamEnd(){}

void OnLoopEnd(void *pBufferContext){}

void OnVoiceError(void *pBufferContext,HRESULT Error){}

};

class Speaker

{public:

//XAudio2数据

IXAudio2* pXAudio2;//XAudio2引擎

IXAudio2MasteringVoice* pMasterVoice;//MsterVoice

VoiceCallBack voiceCallBack;//回调处理

XAUDIO2_BUFFER *pXAudio2Buffer;//封装的用来呈交的音频缓冲数据块

WAVEFORMATEX WaveFormat;//音频格式

IXAudio2SourceVoice *pSourceVoice;//源音处理接口

int MaxBufferCount;//最大缓冲数据块数

int StreamingBufferSize;//缓冲数据块大小

unsigned char **ppAudioData;//音频缓冲数据

bool IsPlaying;//是否在播放

HRESULT State;//状态,0为正常,<0为错误,>0为信息或警告

const wchar_t *pState;//状态内容详细描述

//跟外部读取交换数据

int ReadingBufferNumber;//正在读取的Buffer

int WritingBufferNumber;//正在写入的Buffer

int UnReadingBufferCount;//未呈交Buffer数量

int UnProcessedBufferCount;//呈交但未处理的Buffer数量

int WritingPosition;//当前块准备写入位置

//控制函数部分

public:Speaker();//默认构造函数

public:~Speaker();//析构函数

private:void reset();//重置交换数据参数

private:HRESULT SetState(HRESULT state);//设置简单的状态信息

public:void StopPlaying();//停止播放

public:void Pause();//暂停

public:void StartPlaying();//开始播放

public:void SetFormat(short bits,short channels,int hz);//更改PCM格式

public:void SetBufferSize(int MaxBufferCount,int StreamingBufferSize);//分配音频数据缓冲区

public:static XAUDIO2_BUFFER MakeXAudio2Buffer(const BYTE *pBuffer,int BufferSize);//生成XAudio2缓冲区

public:static WAVEFORMATEX MakePCMSourceFormat(short bits,short channels,int hz);//生成PCM格式信息

public:void ReadData(unsigned char *pBuffer,int length);//从pBuffer指向的内存复制length字节的数据到缓冲区,不复制完不返回

public:int ReadDataFrom(unsigned char *pBuffer,int length);//从pBuffer指向的内存复制length字节的数据,立即返回实际复制的数据字节数

};

void VoiceCallBack::OnBufferEnd(void *pBufferContext)

{

if(pBufferContext == NULL)

{

speaker->pSourceVoice->GetState(&state);

speaker->UnProcessedBufferCount=state.BuffersQueued;

}

else

{

currentcontext = *((int *) pBufferContext)+1;

if(currentcontext > lastcontext)

count += currentcontext - lastcontext;

else  if(currentcontext < lastcontext)

count += speaker->MaxBufferCount + currentcontext - lastcontext;

lastcontext = currentcontext;

speaker->UnProcessedBufferCount -= count;

}

count = 0;

while(speaker->UnReadingBufferCount)//提交

{

speaker->pSourceVoice->SubmitSourceBuffer(&speaker->pXAudio2Buffer[speaker->ReadingBufferNumber],NULL);

speaker->ReadingBufferNumber = (1 + speaker->ReadingBufferNumber) % speaker->MaxBufferCount;

speaker->UnProcessedBufferCount++;

speaker->UnReadingBufferCount --;

}

SetEvent(hBufferEndEvent);

}

Speaker::Speaker()

{

//初始化

IsPlaying = false;

MaxBufferCount = 0;

StreamingBufferSize = 0;

voiceCallBack.speaker = this;

reset();

//建立引擎

if(FAILED(SetState(XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR ))))goto END;

//建立MasteringVoice

if(FAILED(SetState(pXAudio2->CreateMasteringVoice(&pMasterVoice))))goto END;

//分配缓冲内存并设置XAudio2Buffer

SetBufferSize(DEF_MaxBufferCount,DEF_StreamingBufferSize);//设置默认缓冲

//设置pcm格式

WaveFormat = Speaker::MakePCMSourceFormat(16,2,44100);

//建立SourceVoice

SetState(pXAudio2->CreateSourceVoice(&this->pSourceVoice,&this->WaveFormat,0,XAUDIO2_DEFAULT_FREQ_RATIO,&this->voiceCallBack,NULL,NULL));

END:;

};

Speaker::~Speaker()

{

SetBufferSize(0,0);//停止播放并释放缓冲区

if(pSourceVoice != NULL)pSourceVoice->DestroyVoice();

if(pMasterVoice != NULL)pMasterVoice->DestroyVoice();

if(pXAudio2 != NULL)pXAudio2->StopEngine();

}

void Speaker::reset()

{

SetState(0);

ReadingBufferNumber = 0;

UnReadingBufferCount = 0;

UnProcessedBufferCount = 0;

WritingBufferNumber = 0;

WritingPosition = 0;

voiceCallBack.count = 0;

voiceCallBack.lastcontext = 0;

}

void Speaker::StopPlaying()

{

if(pSourceVoice == NULL)return;

XAUDIO2_VOICE_STATE state;

if(IsPlaying)

{

IsPlaying = false;

pSourceVoice->GetState(&state);

while(state.BuffersQueued)

{

if(FAILED(SetState(pSourceVoice->Stop(0,XAUDIO2_COMMIT_NOW))))return;

if(FAILED(SetState(pSourceVoice->FlushSourceBuffers())))return;

Sleep(1);

pSourceVoice->GetState(&state);

}

}

reset();

}

void Speaker::Pause()

{

if(pSourceVoice == NULL)return;

if(IsPlaying)

{

SetState(pSourceVoice->Stop(0,XAUDIO2_COMMIT_NOW));

if(FAILED(State))return;

IsPlaying = false;

}

}

void Speaker::StartPlaying()

{

SetState(pSourceVoice->Start(0,XAUDIO2_COMMIT_NOW));

if(FAILED(State))return;

this->IsPlaying = true;

}

void  Speaker::SetFormat(short bits,short channels,int hz)

{

if(WaveFormat.wBitsPerSample == bits && WaveFormat.nChannels == channels && WaveFormat.nSamplesPerSec == hz)

return;

StopPlaying();

if(pSourceVoice)pSourceVoice->DestroyVoice();

pSourceVoice = NULL;

WaveFormat = MakePCMSourceFormat(bits,channels,hz);

if(FAILED(SetState(pXAudio2->CreateSourceVoice(&pSourceVoice,&WaveFormat,0,XAUDIO2_DEFAULT_FREQ_RATIO,&this->voiceCallBack,NULL,NULL))))pSourceVoice = NULL;

}

void Speaker::SetBufferSize(int MaxBufferCount,int StreamingBufferSize)

{

if (this->MaxBufferCount!=MaxBufferCount || this->StreamingBufferSize!=StreamingBufferSize)

{

this->StopPlaying();

for(int i=0;i<this->MaxBufferCount;++i)

{

if(this->StreamingBufferSize)//删除块

{

delete [] this->ppAudioData[i];

if(this->pXAudio2Buffer[i].pContext)

delete this->pXAudio2Buffer[i].pContext;

}

}

if(this->MaxBufferCount)//删除所有

{

delete [] this->ppAudioData;

delete [] this->pXAudio2Buffer;

}

this->MaxBufferCount=MaxBufferCount;//赋值

this->StreamingBufferSize=StreamingBufferSize;

voiceCallBack.lastcontext = 0;

if(MaxBufferCount)//创建

{

reset();

this->ppAudioData = new unsigned char *[MaxBufferCount];

this->pXAudio2Buffer = new XAUDIO2_BUFFER[MaxBufferCount];

if (StreamingBufferSize)

{

this->pXAudio2Buffer = new XAUDIO2_BUFFER[MaxBufferCount];

for(int i=0;i<MaxBufferCount;++i)

{

this->ppAudioData[i] = new unsigned char[StreamingBufferSize];

this->pXAudio2Buffer[i] = Speaker::MakeXAudio2Buffer(ppAudioData[i],StreamingBufferSize);

*((int*)this->pXAudio2Buffer[i].pContext) = i;

}

}

}

}

}

XAUDIO2_BUFFER Speaker::MakeXAudio2Buffer(const BYTE *pBuffer,int BufferSize)

{

XAUDIO2_BUFFER XAudio2Buffer;

XAudio2Buffer.AudioBytes = BufferSize;

XAudio2Buffer.Flags = 0;

XAudio2Buffer.LoopBegin = 0;

XAudio2Buffer.LoopCount = 0;

XAudio2Buffer.LoopLength = 0;

XAudio2Buffer.pAudioData = pBuffer;

XAudio2Buffer.pContext = (void*)new int[1];

XAudio2Buffer.PlayBegin = 0;

XAudio2Buffer.PlayLength = 0;

return XAudio2Buffer;

}

WAVEFORMATEX Speaker::MakePCMSourceFormat(short bits,short channels,int hz)

{

WAVEFORMATEX format;

format.wFormatTag = WAVE_FORMAT_PCM;//PCM格式

format.wBitsPerSample = bits;//位数

format.nChannels = channels;//声道数

format.nSamplesPerSec = hz;//采样率

format.nBlockAlign = bits*channels/8;//数据块调整

format.nAvgBytesPerSec = format.nBlockAlign*hz;//平均传输速率

format.cbSize = 0;//附加信息

return format;

}

void Speaker::ReadData(unsigned char *pBuffer,int length)

{

int i=0;

while(length>i)//不读完不退出循环

{

while(UnProcessedBufferCount + UnReadingBufferCount

>= MaxBufferCount-1)

{

if(!IsPlaying)

{

StartPlaying();

Sleep(0);

continue;

}

voiceCallBack.OnBufferEnd(NULL);

Sleep(10);

}

if(StreamingBufferSize > length-i+WritingPosition)

{

while(i<length)

{

this->ppAudioData[WritingBufferNumber][WritingPosition] = pBuffer[i];

++WritingPosition;

++i;

}

break;

}

while(StreamingBufferSize>WritingPosition)

{

this->ppAudioData[WritingBufferNumber][WritingPosition] = pBuffer[i];

++WritingPosition;

++i;

}

WritingPosition = 0;

WritingBufferNumber = (1+WritingBufferNumber)%MaxBufferCount;

++UnReadingBufferCount;

}

}

int Speaker::ReadDataFrom(unsigned char *pBuffer,int length)//从pBuffer指向的内存复制length字节的数据,立即返回实际复制的数据字节数

{

int i=0;

//XAUDIO2_VOICE_STATE state;

//pSourceVoice->GetState(&state);

if(pBuffer==nullptr || !length)

return 0;

while(UnProcessedBufferCount + UnReadingBufferCount < this->MaxBufferCount)

{

if(this->StreamingBufferSize > length-i+WritingPosition)

{

while(i<length)

{

this->ppAudioData[WritingBufferNumber][WritingPosition] = pBuffer[i];

++WritingPosition;

++i;

}

return length;

}

while(WritingPosition<StreamingBufferSize)

{

this->ppAudioData[WritingBufferNumber][WritingPosition] = pBuffer[i];

++WritingPosition;

++i;

}

WritingPosition = 0;

WritingBufferNumber = (1+WritingBufferNumber)%MaxBufferCount;

++UnReadingBufferCount;

++UnProcessedBufferCount;

}

voiceCallBack.OnBufferEnd(NULL);//督促XAudio2快点放完

return i;

}

HRESULT Speaker::SetState(HRESULT state)

{

this->State = state;

switch(state)

{

case 0:pState = L"正常.";break;

case XAUDIO2_E_INVALID_CALL:pState = L"函数无效调用";break;

case XAUDIO2_E_XMA_DECODER_ERROR:pState = L"XMA设备损坏";break;

case XAUDIO2_E_XAPO_CREATION_FAILED:pState = L"XAPO效果初始化失败";break;

case XAUDIO2_E_DEVICE_INVALIDATED:pState = L"音频设备不可用";break;

default:if(state>0)pState = L"未知信息";

else pState = L"未知错误";

}

return state;

}

声明:不知道此文章原始出处是哪里,所以没有注明转载地址。网上可以搜到很多这篇文章相关的文档或者引用,如果原作者需要我注明地址的话,请联系我。

时间: 2024-08-06 05:31:15

C++编程:XAudio2 API应用示例的相关文章

Linux程序设计学习笔记----网络通信编程API及其示例应用

转载请注明出处, http://blog.csdn.net/suool/article/details/38702855. BSD Socket 网络通信编程 BSD TCP 通信编程流程 图为面向连接的Socket通信的双方执行函数流程.使用TCP协议的通信双方实现数据通信的基本流程如下 建立连接的步骤 1.首先服务器端需要以下工作: (1)调用socket()函数,建立Socket对象,指定通信协议. (2)调用bind()函数,将创建的Socket对象与当前主机的某一个IP地址和TCP端口

Socket编程(c语言示例)

转自:http://blog.csdn.net/dxpqxb/article/details/8166423 前言 Socket可以看成在两个程序进行通讯连接中的一个端点,是连接应用程序和网络驱动程序的桥梁,Socket在应用程序中创建,通过绑定与网络驱动建立 关系.此后,应用程序送给Socket的数据,由Socket交网络驱动程序向网络上发送出去.计算机从网络上收到与该Socket绑定IP地址和端口号 相关的数据后,由网络驱动程序交给Socket,应用程序便可从该Socket中提取接收到得数据

【DOM编程艺术】综合示例

index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Jay Skript And The Domsters</title> <script src="scripts/modernizr-1.6.min.js"></script> <l

速码验证码接码平台API接入示例说明

速码平台API接口示例[通用版] 一.统一说明 接口地址:http://api.eobzz.com/httpApi.do?action= 接口统一编码:UTF-8 接口调用方式: HTTP,支持GET和POST两种方式. GET方式调用实例:http://api.eobzz.com/httpApi.do?action=方法名&参数1=值&参数2=值(具体方法名及参数请参考接口方法). 软件开发者说明:服务器返回no_data时表示系统暂时没有可用号码了,请使用死循环每隔一分钟请求一次手机号

Html5之高级-14 Web Socket(概述、API、示例)

一.Web Socket 概述 Web Socket 简介 - Web Socket 是 HTML5 提供的在 Web应用程序中客户端与服务器端之间进行的非 HTTP 的通信机制 - Web Socket 实现了用 HTTP 不容易实现的服务器端的数据推送等智能通讯技术 Web Socket 的特点 - Web Socket 可以在服务器与客户端之间建立一个非 HTTP 的双向连接 - 这个连接时实时的,也是永久的 - 服务器端可以主动推送消息 - 服务器端不再需要轮询客户端的请求 - 服务器端

SharePoint 2013 Search REST API 使用示例

原文:SharePoint 2013 Search REST API 使用示例 前言:在SharePoint2013中,提供Search REST service搜索服务,你可以在自己的客户端搜索方法或者移动应用程序中使用,该服务支持REST web request.你可以使用KeyWord Query Language(KQL)或者FAST Query Language(FQL)来对Search REST Service进行搜索查询,并且,试用与远程客户端应用程序.移动应用程序和其他应用程序.

ASP.NET Web API 开篇示例介绍

ASP.NET Web API 开篇示例介绍 ASP.NET Web API 对于我这个初学者来说ASP.NET Web API这个框架很陌生又熟悉着. 陌生的是ASP.NET Web API是一个全新的框架,对于这个框架在一个项目中起到的作用我暂且还不是很清楚这里也就不妄下结论了,说实话不是我不想而是我无能为力,只能自己去摸索试着去了解它. 熟悉的是ASP.NET Web API跟ASP.NET MVC的框架结构一开始看起来有一些相似的地方. 话就不多说了,大家就和我一起来学习ASP.NET

UNIX网络编程-基本API介绍(一)

1.基本结构 大多数套接口函数都需要一个指向套接口地址结构的指针作为参数.每个协议族都定义它自己的套接口地址结构.这些结构的名字均以“sockaddr_”开头,并以对应每个协议族的唯一后缀结束. 1.1 IPv4套接口地址结构 也称为“网际套接口地址结构”,以“sockaddr_in”命名,在头文件<netinet/in.h>中. struct in_addr { in_addr_t s_addr; //32为IP地址 }; struct sockaddr_in { uint8 sin_len

Web API 简单示例

原文:Web API 简单示例 一.RESTful和Web API Representational State Transfer (REST) is a software architecture style consisting of guidelines and best practices for creating scalable web services. REST is a coordinated set of constraints applied to the design o