vc 与webservice通信的几种方法

            

        vc 与webservice通信有这么几种方法,现在总结一下。

        首先webservice服务会提供接口,接口的说明都会放在一个wsdl文档中。没有接触过vc与webservice通信的开发人员拿到这个接口说明文档时可能无从下手, 下面说第一种方法。

         1. 利用sproxy.exe 生成一个代理类。

             vc的安装目录下,在bin目录下会有sproxy.exe 这样一个工具(vs2008下没有,需要下载源码编译成sproxy.exe放到bin目录下),然后在dos下,执行如下命令sproxy.exe  /wsdl /namespace:xxx    yyy.wsdl /out:zzz.h。yyy.wsdl 是webservice的接口描述文档,zzz.h是生成的头文件,在zzz.h中,有soap消息包封装的定义等等,我们需要的就是这个头文件。在我们的工程中包含这个头文件zzz.h,

         在这个头文件中,有命名空间的定义也就是namespace:xxx.

         工程中需要using namespace xxx;

         模板定义 typedef  CFuncT<> Func;   //头文件中包含这个模板定义,直接拷贝过来加入到工程。

         调用接口前需要初始化com组件。

         如下方式

          #include “zzz.h”

using namespace xxx;

typedef CFuncT<> Func;

CoInitialize(NULL);
xxx::CFunc ws;
ws.SetUrl(strAddress);
HRESULT hr = ws.Func(temp, &str);  //Func 为wsdl中描述的接口
CoUninitialize();

     2.   使用com组件自己封装soap包

             这个方法需要依赖一些com组件(WHSC30.dll,MSSOAPR3.dll,MSSOAP30.dll,msxml4.dll)

没有这些com dll的机器需要按上面顺序注册一下,注意编译时有的机器也需要注册这些com组件。

HRESULT   hr;  
 ISoapConnectorPtr   SoapConnector;  
 ISoapSerializerPtr   Serializer;  
 ISoapReaderPtr   Reader;
 try  
 {  
  hr = CoInitialize(NULL);//初始化com环境
  if(FAILED(hr))
  {
            OutputDebugString("初始化com环境失败\n");
   return   " ";
  }
  CString chNameSpace =  "http://sms.ha.mocha.com/"; //命名空间
  //创建SoapConnector类的对象  
  hr = SoapConnector.CreateInstance(__uuidof(HttpConnector30));      
  if(FAILED(hr))
  {
   OutputDebugString("创建SoapConnector类的对象失败\n");
   return   " ";
  }

  //指定Web服务的地址  
  SoapConnector-> Property["EndPointURL"]= (_bstr_t)"http://sms.ha.mocha.com:8080/haSms/Func";//接口的ip地址

  //与Web服务连接  
  hr=SoapConnector-> Connect();  
  if(FAILED(hr))
  {
   OutputDebugString("与web服务连接失败\n");
   return   " ";  
  }

  //指定Web服务完成的操作  
  SoapConnector-> Property ["SoapAction"]= chNameSpace.GetBuffer()   +   _bstr_t( "Func");  
  chNameSpace.ReleaseBuffer();

  //准备发送消息给Web服务  
  hr=SoapConnector-> BeginMessage();  
  if(FAILED(hr))
  {
            OutputDebugString("准备发送消息给Web服务失败\n");
   return   " ";
  }
  //   创建SoapSerializer对象  
  hr=Serializer.CreateInstance(__uuidof(SoapSerializer30));  
  if(FAILED(hr))
  {
   OutputDebugString("创建序列化对象失败\n");
   return   " ";
  }
  //   将serializer连接到connector的输入字符串  
  hr=Serializer-> Init(_variant_t((IUnknown*)SoapConnector-> InputStream));  
  if(FAILED(hr))
  {
   OutputDebugString("连接到connector失败\n");
   return   " ";
  }
  //   创建SOAP消息  

  Serializer->StartEnvelope("soap", "", "");
  Serializer->SoapAttribute("xsi", "", "http://www.w3.org/2001/XMLSchema-instance", "xmlns");
  Serializer->SoapAttribute("xsd", "", "http://www.w3.org/2001/XMLSchema", "xmlns");
  Serializer->StartBody("");    
  Serializer-> StartElement( "Func", (_bstr_t)chNameSpace, " ", "");
  Serializer->SoapAttribute("xmlns", "", (_bstr_t)chNameSpace, "");

  Serializer-> StartElement( "arg0", (_bstr_t)chNameSpace, "NONE", "");  
  Serializer->WriteString((_bstr_t)UserName);
  Serializer-> EndElement();  

  Serializer-> StartElement( "arg1", (_bstr_t)chNameSpace, "NONE", "");  
  Serializer->WriteString((_bstr_t)Password);
  Serializer-> EndElement();

   Serializer-> StartElement( "arg2", (_bstr_t)chNameSpace, "NONE", "");
  Serializer->WriteString("");
  Serializer-> EndElement();


  Serializer-> EndElement();
  Serializer-> EndBody();  
  Serializer-> EndEnvelope();

  //消息真正地发给Web服务  
  hr=SoapConnector-> EndMessage();
  if(FAILED(hr))
  {
   OutputDebugString("正真发送消息时失败\n");
   return   " ";  
  }

  //   读取响应  
  Reader.CreateInstance(__uuidof(SoapReader30));  

  //   将reader联接到connector的输出字符串  
  Reader-> Load(_variant_t((IUnknown*)SoapConnector-> OutputStream),   _T( " "));   
   
   return   CString((const   char   *)Reader-> RpcResult->text);  
 }  
 catch  (_com_error   e)  
 {  
  CString str = (CString)(char*)e.Description();
  OutputDebugString(str);
  return   str;

    }

3.抛弃接口,直接发送http包。

使用这种办法需要用抓包工具抓到正确的soap包,按照包的格式通过socket向接口地址发送post请求,下面是抓的包

POST /GetList.asmx?op=GetString HTTP/1.0

Content-Type: text/xml; charset=UTF-8

SOAPAction: ""

Accept: */*

User-Agent: Apache CXF 2.2.9

Cache-Control: no-cache

Pragma: no-cache

Host: 192.168.88.247:111

Connection: keep-alive

Content-Length: 279

 

http://schemas.xmlsoap.org/soap/envelope/"> xmlns:ns2="http://sms.ha.mocha.com/">vrv12345613691234567...........................:869377>

就按这种格式去发包就可以实现,实际就是用socket将这些字符串发送出去,在接受缓冲区里得到接口返回给我们的数据。具体发送可以搜索一下这个request类。主要代码如下:

int Request::SendHTTP(LPCSTR url,LPCSTR headerReceive,BYTE *post,
DWORD postLength,HTTPRequest *req)
{
WSADATA WsaData;
SOCKADDR_IN sin;
SOCKET sock;
char buffer[512];
char protocol[20],host[256],request[1024];
int l,port,chars,err;
MemBuffer headersBuffer,messageBuffer;
char headerSend[1024];
BOOL done;




ParseURL(url,protocol,sizeof(protocol),host,sizeof(host), // Parse the URL
request,sizeof(request),&port);
if(strcmp(protocol,"HTTP"))
return 1;

err = WSAStartup (0x0101, &WsaData); // Init Winsock
if(err!=0)
return 1;

sock = socket (AF_INET, SOCK_STREAM, 0);
//if (socket == INVALID_SOCKET)
if (sock == INVALID_SOCKET)
{
OutputDebugString("创建套接字失败!\n");
return 1;
}

/*//设置非阻塞
unsigned long uFlag = 1;
int nRet = ioctlsocket(sock,FIONBIO,(unsigned long*)&uFlag);
if(nRet == SOCKET_ERROR)
return 1;*/

sin.sin_family = AF_INET; //Connect to web sever
sin.sin_port = htons( (unsigned short)port );
sin.sin_addr.s_addr = GetHostAddress(host);

if( connect (sock,(LPSOCKADDR)&sin, sizeof(SOCKADDR_IN) ) )
{
OutputDebugString("sokcet 连接失败!\n");
return 1;
}

if( !*request )
lstrcpyn(request,"/",sizeof(request));

if( post == NULL )
{
SendString(sock,"GET ");
strcpy(headerSend, "GET ");
}
else
{
SendString(sock,"POST ");
strcpy(headerSend, "POST ");
}
SendString(sock,request);
strcat(headerSend, request);

SendString(sock," HTTP/1.0\r\n");
strcat(headerSend, " HTTP/1.0\r\n");

if( (headerReceive!=NULL) && *headerReceive )
{
SendString(sock,headerReceive);
strcat(headerSend, headerReceive);
}

SendString(sock, "SOAPAction: \"\"\r\n");
strcat(headerSend, "SOAPAction: \"\"\r\n");

SendString(sock,"Accept: */*\r\n");
strcat(headerSend, "Accept: */*\r\n");

SendString(sock,"User-Agent: Apache CXF 2.2.9\r\n");
strcat(headerSend, "User-Agent: Apache CXF 2.2.9\r\n");

SendString(sock, "Cache-Control: no-cache\r\n");
strcat(headerSend, "Cache-Control: no-cache\r\n");

SendString(sock, "Pragma: no-cache\r\n");
strcat(headerSend, "Pragma: no-cache\r\n");

SendString(sock,"Host: ");
strcat(headerSend, "Host: ");

//将地址格式化
char buf[10]={0};
itoa(port, buf, 10);
strcat(host,":");
strcat(host, buf);

SendString(sock,host);
strcat(headerSend, host);

SendString(sock,"\r\n");
strcat(headerSend, "\r\n");

SendString(sock, "Connection: keep-alive\r\n");
strcat(headerSend, "Connection: keep-alive\r\n");

if(postLength)
{
wsprintf(buffer,"Content-Length: %ld\r\n",postLength);
SendString(sock,buffer);
strcat(headerSend, buffer);
}

SendString(sock,"\r\n"); // Send a blank line to signal end of HTTP headerReceive
strcat(headerSend, "\r\n");

if( (post!=NULL) && postLength )
{
send(sock,(const char*)post,postLength,0);
post[postLength] = '\0';

strcat(headerSend, (const char*)post);
}

req->headerSend = (char*) malloc( sizeof(char*) * strlen(headerSend));
strcpy(req->headerSend, (char*) headerSend );


MemBufferCreate(&headersBuffer );
chars = 0;
done = FALSE;
//接受接口返回的数据。
while(!done)
{
l = recv(sock,buffer,1,0);
if(l<0)
done=TRUE;

switch(*buffer)
{
case '\r':
break;
case '\n':
if(chars==0)
done = TRUE;
chars=0;
break;
default:
chars++;
break;
}

MemBufferAddByte(&headersBuffer,*buffer);
}

req->headerReceive = (char*) headersBuffer.buffer;
*(headersBuffer.position) = 0;



MemBufferCreate(&messageBuffer); // Now read the HTTP body

do
{
l = recv(sock,buffer,sizeof(buffer)-1,0);
if(l<0)
break;
*(buffer+l)=0;
MemBufferAddBuffer(&messageBuffer, (unsigned char*)&buffer, l);
} while(l>0);
*messageBuffer.position = 0;
req->message = (char*) messageBuffer.buffer;
req->messageLength = (messageBuffer.position - messageBuffer.buffer);


closesocket(sock); // Cleanup

return 0;
}

你可能感兴趣的:(vc 与webservice通信的几种方法)