SOAP和HTTP关系,以及TCP/IP和SOCKET通讯知识,以及C语言实现socket通讯

SOAP和HTTP关系

SOAP:简单对象访问协议是交换数据的一种协议规范,是一种轻量的、简单的、基于XML(标准通用标记语言下的一个子集)的协议,它被设计成在WEB上交换结构化的和固化的信息。

构建模块
一条 SOAP 消息就是一个普通的 XML 文档,包含下列元素:
必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息
可选的 Header 元素,包含头部信息
必需的 Body 元素,包含所有的调用和响应信息
可选的 Fault 元素,提供有关在处理此消息所发生错误的信息
语法规则
这里是一些重要的语法规则:
SOAP 消息必须用 XML 来编码
SOAP 消息必须使用 SOAP Envelope 命名空间
SOAP 消息必须使用 SOAP Encoding 命名空间
SOAP 消息不能包含 DTD 引用
SOAP 消息不能包含 XML 处理指令

HTTP:HTTP协议目的是规定客户端和服务端数据传输的格式和数据交互行为,并不负责数据传输的细节。底层是基于TCP实现的。
常用的请求方法:GET/POST/DELETE/PUT
常见的响应的状态码:200OK/400Bad Request/403Forbidden/404Not Found/500Internal Server Error/

HTTP是一个通信协议,通过网络传输信息。

SOAP
是一个基于XML的协议交换消息,可以使用HTTP来传输这些信息。事实上HTTP是SOAP消息的最常见的传输工具。soap将信息进行XML的序列化后,再用http协议的方式再打包进行传送,传送的方式还是tcp或者udp。

SOAP采用了已经广泛使用的两个协议:HTTP 和XML(标准通用标记语言下的一个子集)。HTTP用于实现 SOAP 的RPC 风格的传输, 而XML 是它的编码模式。
SOAP 通讯协议使用 HTTP 来发送XML 格式的信息。
soap将信息进行XML的序列化后,再用http协议的方式再打包进行传送,传送的方式还是tcp或者udp。
做个比喻就好理解了:tcp 和 udp 都是公路,暂且把tcp认为是一般公路,udp高速公路,soap和http就都是汽车,那么soap和http都可以在tcp和udp上跑。
说soap可以通过http来传送,实际就是说soap是小轿车,http是装轿车的卡车,把soap的信息装到http里面,然后再运输,当然走的道路还是tcp或udp。
说soap可以通过http协议来传输,这句话不太准确,比较准确第说法是:soap信息可以通过http协议包装后通过tcp或udp传输。

TCP相关知识

TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯。
TCP提供的是一种可靠的数据流服务,采用“带重传的肯定确认”技术来实现传输的可靠性。TCP还采用一种称为“滑动窗口”的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。
如果IP数据包中有已经封好的TCP数据包,那么IP将把它们向‘上’传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路间的连接。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
TCP将它的信息送到更高层的应用程序,例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。
面向连接的服务(例如Telnet、FTP、rlogin、X Windows和SMTP)需要高度的可靠性,所以它们使用了TCP。DNS在某些情况下使用TCP(发送和接收域名数据库),但使用UDP传送有关单个主机的信息。

IP

IP层接收由更低层(网络接口层例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层—TCP或UDP层;相反,IP层也把从TCP或UDP层接收来的数据包传送到更低层。IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是否按顺序发送的或者有没有被破坏,IP数据包中含有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址)。
高层的TCP和UDP服务在接收数据包时,通常假设包中的源地址是有效的。也可以这样说,IP地址形成了许多服务的认证基础,这些服务相信数据包是从一个有效的主机发送来的。IP确认包含一个选项,叫作IP source routing,可以用来指定一条源地址和目的地址之间的直接路径。对于一些TCP和UDP的服务来说,使用了该选项的IP包好像是从路径上的最后一个系统传递过来的,而不是来自于它的真实地点。这个选项是为了测试而存在的,说明了它可以被用来欺骗系统来进行平常是被禁止的连接。那么,许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。

socket通讯知识

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

服务端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SERVER_PORT 8888
#define QUEUE 20
int main( ){

    int socket_fd;
    struct sockaddr_in sock_server;   /*服务器sockaddr*/
    struct sockaddr_in sock_client;   /*客户端sockaddr*/
    int sockfd; 
    int len = 0;
    char buff[1024+1];

    memset( &sock_server, 0x00, sizeof( sock_server ) );
    memset( &sock_client, 0x00, sizeof( sock_client ) );

    /*创建套接字*/
    socket_fd = socket( AF_INET, SOCK_STREAM, 0 );

    sock_server.sin_family= AF_INET;
    sock_server.sin_port = htons( SERVER_PORT );
    sock_server.sin_addr.s_addr = htonl( INADDR_ANY );

    /*bind为套接字sockfd指定本地地址my_addr.my_addr的长度为addrlen(字节).传统的叫法是给一个套接字分配一个名字.
     *当使用 socket(),函数创建一个套接字时,它存在于一个地址空间(地址族), 但还没有给它分配一个名字
     *一般来说在使用 SOCK_STREAM 套接字建立连接之前总要使用 bind 为其分配一个本地地址*/
    if( bind( socket_fd, (struct sockaddr *)&sock_server, sizeof( sock_server ) ) == -1){
        perror( "bind error" );        
        exit(1);
    }
    printf( "bind success,port:%d\n", SERVER_PORT ); 

    /*在接收连接之前,首先要使用socket()创建一个套接字,然后调用listen()使其能够自动接收到来的连接并且为连接队列指定一个长度限制.
     *之后就可以使用 accept() 接收连接.listen()调用仅适用于 SOCK_STREAM 或者 SOCK_SEQPACKET 类型的套接字.
     *参数 backlog 指定未完成连接队列的最大长度.如果一个连接请求到达时未完成连接,队列已满,那么客户端将接收到错误:ECONNREFUSED.
     *或者,如果下层协议支持重发,那么这个连接请求将被忽略,这样客户端 在重试的时候就有成功的机会*/
    if( listen( socket_fd, QUEUE ) == -1 ){
        perror( "listen error." );
        exit(1);
    }  
    printf( "listen success.\n" ); 

    while( 1 ){

        len = sizeof( sock_client );
        sockfd = accept( socket_fd, (struct sockaddr *)&sock_client, (socklen_t *)&len );
        if( sockfd < 0 ){
            continue;
        }   
        printf( "accept() success.\n" );
        printf( "RECV:[%d],IP=%s,PORT=%d\n", sockfd, inet_ntoa(sock_client.sin_addr), ntohs(sock_client.sin_port) ); 
     
        while( 1 ){
           memset( buff, 0x00, sizeof( buff ) ); 
           if( recv( sockfd, buff, sizeof( buff )-1, 0 ) < 0 ){
               close( sockfd );
               printf( "recv error.\n" );
               break;
           }
           printf( "RECV FROM CLIENT:%s", buff  ); 
           if( !memcmp( buff, "exit", 4 ) ){
               close( sockfd );
               printf( "close sockfd\n" );  
               break;
           } 

           /*send*/
           fflush( stdin );
           memset( buff, 0x00, sizeof( buff ) );
           printf( "SERVER:" );

           memset( buff, 0x00, sizeof( buff ) );
           if( NULL == ( fgets( buff, sizeof( buff )-1, stdin ) ) ){
               perror( "fgets error.\n" ); 
               close( sockfd );
               fflush( stdin );
               break; 
           }
           fflush( stdin );
           
           send( sockfd, buff, sizeof( buff )-1, 0 ); 
           if( memcmp( buff, "exit", 4 ) == 0 || memcmp( buff, "kill", 4 ) == 0 ){
               close( sockfd );
               printf( "close client socket.\n" );  
               break;
           }
        }

        if( !memcmp( buff, "kill", 4 ) ){
            close( sockfd );
            printf( "close server socket.\n" );
            break;
        }
    }
    exit(0);
}

客户端代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

#define SERVER_IP "192.168.137.10"
#define SERVER_PORT 8888

int main( ){

    int sockfd;
    struct sockaddr_in serverAddr;
    int len = 0;
    int iRet = 0;
    char buff[128];

    memset( &serverAddr, 0x00, sizeof( serverAddr ) );
    memset( buff, 0x00, sizeof( buff ) );

    sockfd = socket( AF_INET, SOCK_STREAM, 0 );
    if( sockfd < 0 ){
        printf( "socket() errror:%s", strerror( errno ) );
        exit(1);
    }

    /*Convert server IP and PORT*/
    serverAddr.sin_family = AF_INET;   /*ipv4*/
    serverAddr.sin_addr.s_addr = inet_addr( SERVER_IP );
    serverAddr.sin_port = htons( SERVER_PORT );
    
    len = sizeof( serverAddr );
    iRet = connect( sockfd, ( struct sockaddr *) &serverAddr, (socklen_t) len );
    if( iRet < 0 ){
        printf( "connect() error:%s", strerror(errno) );
        exit(1);
    }
    printf( "connect success.\n" );

    printf( "begin to communicate.\n" );

    while( 1 ){
        memset( buff, 0x00, sizeof( buff ) );
        printf( "CLIENT:" );
        fflush( stdin ); 
        if( fgets( buff, sizeof( buff )-1, stdin ) == NULL ){
            printf( "fgets() error.\n" );
            fflush( stdin );
            exit(1);
        }
        fflush( stdin );
       
        /*send*/ 
        iRet = send( sockfd, buff, strlen(buff), 0 );
        if( iRet < 0 ){
            printf( "send() error:%s", strerror(errno) );
            exit(1);
        }
        if( !memcmp( buff, "exit", 4 ) ){
            printf( "close connection.\n" );
            close( sockfd );
            break;
        }
        
        /*recv*/
        memset( buff, 0x00, sizeof( buff ) );
        if( recv( sockfd, buff, sizeof(buff)-1, 0 ) < 0 ){
            printf( "recv error:%s", strerror( errno ) );
            close( sockfd );
            break;
        }
        printf( "RECV FROM SERVER:%s", buff );
       
        if( !memcmp( buff, "exit", 4 ) || !memcmp( buff, "kill", 4 ) ){
            printf( "close socket.\n" );
            close( sockfd );
            break;
        }

    }

    exit(0);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gSOAP编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。绝大多数的C++web服务工具包提供一组API函数类库来处理特定的SOAP数据结构,这样就使得用户必须改变程序结构来适应相关的类库。与之相反,gSOAP利用编译器技术提供了一组透明化的SOAP API,并将与开发无关的SOAP实现细节相关的内容对用户隐藏起来。   gSOAP的编译器能够自动的将用户定义的本地化的C或C++数据类型转变为符合XML语法的数据结构,反之亦然。这样,只用一组简单的API就将用户从SOAP细节实现工作中解脱了出来,可以专注与应用程序逻辑的实现工作了。gSOAP编译器可以集成C/C++和Fortran代码(通过一个Fortran到C的接口),嵌入式系统,其他SOAP程序提供的实时软件的资源和信息;可以跨越多个操作系统,语言环境以及在防火墙后的不同组织。   gSOAP使编写web服务的工作最小化了。gSOAP编译器生成SOAP的代码来序列化或反序列化C/C++的数据结构。gSOAP包含一个WSDL生成器,用它   来为你的web服务生成web服务的解释。gSOAP的解释器及导入器可以使用户不需要分析web服务的细节就可以实现一个客户端或服务端程序。   下面是gSOAP的一些特点:   ×gSOAP编译器可以根据用户定义的C和C++数据结构自动生成符合SOAP的实例化代码。   ×gSOAP支持WSDL 1.1, SOAP 1.1, SOAP 1.2, SOAP RPC 编码方式以及 literal/document 方式.   ×gSOAP是少数完全支持SOAP1.1 RPC编码功能的工具包,包括多维数组及动态类型。比如,一个包含一个基类参数的远程方法可以接收客户端   传来的子类实例。子类实例通过动态绑定技术来保持一致性。   ×gSOAP 支持 MIME (SwA) 和 DIME 附件包。   ×gSOAP是唯一支持DIME附件传输的工具包。它允许你在保证XML可用性的同时能够以最快的方式(流方式)传递近乎无大小限制的二进制数据   。   ×gSOAP 支持 SOAP-over-UDP。   ×gSOAP 支持 IPv4 and IPv6.   ×gSOAP 支持 Zlib deflate and gzip compression(for HTTP, TCP/IP, and XML file storage)。   ×gSOAP 支持 SSL (HTTPS)。   ×gSOAP 支持 HTTP/1.0, HTTP/1.1 保持连接, 分块传输及基本验证。   ×gSOAP 支持 SOAP 单向消息。   ×gSOAP 包含一个 WSDL 生成器,便于web服务的发布。   ×gSOAP 包含一个WSDL解析器(将WSDL转换为gSOAP头文件),可以自动化用户客户端及服务端的开发。   ×生成可以单独运行的web服务及客户端程序。   ×因为只需要很少内存空间,所以可以运行在类似Palm OS, Symbian, Pocket PC的小型设备中。   ×适用于以C或C++开发的web服务中。   ×跨平台:Windows, Unix, Linux, Mac OS X, Pocket PC, Palm OS, Symbian等。   ×支持序列化程序中的本地化C/C++数据结构。   ×可以使用输入和输出缓冲区来提高效率,但是不用完全消息缓冲来确定HTTP消息的长度。取而代之的是一个三相序列化方法。这样,像64位   编码的图像就可以在小内存设备(如PDA)中以DIME附件或其他方式传输。   ×支持C++单继承,动态绑定,重载,指针结构(列表、树、图、循环图,定长数组,动态数组,枚举,64位2进制编码及16进制编码)。   ×不需要重写现有的C/C++应用。但是,不能用unions,指针和空指针来作为远程方法调用参数的数据结构中元素。   ×三相编组:1)分析指针,引用,循环数据结构;2)确定HTTP消息长度;3)将数据序列化位SOAP1.1编码方式或用户定义的数据编码方式。   ×双相编组:1)SOAP解释及编码;2)分解“forward”指针(例如:分解SOAP中的href属性)。   ×完整可定制的SOAP错误处理机制。   ×可定制的SOAP消息头处理机制,可以用来保持状态信息   2 gSoap2.2版与gSOAP 2.1版(或以前版本)的不同   如果你是从2.1版升级到2.2或以后版本,请注意这些变化。   为了能够分离传输、内容编码、映射中的接收/发送设置,改变了运行时选项及标志。这些标志分布再四个类中:传输(IO),内容编码(ENC   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值