linux c使用socket进行http 通信,并接收任意大小的http响应

Posted 南极上的雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux c使用socket进行http 通信,并接收任意大小的http响应相关的知识,希望对你有一定的参考价值。

终于说到SOCKET 这里了。SOCKET进行http通信的实际就是利用socket将http请求信息发送给http服务器,然后再利用socket接收http响应。

由于本文与之通信的服务器是ip已知的,所以为了能够将能够和互联网网站进行http通信还要另外像办法。

代码如下:

(1)http.h

//http.c当中可能被其他程序锁用到的函数的声明
#include "http_url.h"
#ifndef http_h
#define http_h
typedef struct sockaddr_in ip;
typedef struct sockaddr *IP;
extern char cookie[200];
extern int create_socket();
extern void init_ip(ip *httpip,char *Ip,int port);
extern int Bind(int socket,ip *httpip);
extern int get_other_socket(int socket);
extern int Connect(int socket,ip* httpip);
extern int Send(int socket,char *Data);
extern char* Read(int socket);
extern int http_perform_url(PURL url,char **Buffer);
extern int find_cookie(char *Cookie,char *httpBuffer);
extern void randomCode(char *result);
extern void Set_Cookie(char *cookie_);
extern void httpBuffer_free(char **respond);
#endif // http_h

(2)http.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include "http_url.h"//加入http_hrl模块
#include "data2.h"//加入data2模块,data2模块用于存储和处理HTTP响应
#define SETCOOKIE "Set-Cookie: "
#define SENDSIZE 4096//每次发送数据的大小,注:未使用

#define http_h
//注意:本文件所有定义函数只适合HTTP通信----排除某些例外函数
//用sockaddr_in、struct sockaddr *结构体存储IP
typedef struct sockaddr_in ip;
typedef struct sockaddr *IP;

//全局变量cookie,注:目前仅支持一个cookie
char cookie[200];

int is_respond_ok(char *httpBuffer);

//自定义创建socket的函数
//返回值:成功返回socket嵌套字,失败返回-1
int create_socket()
{
    int temp;
    temp=socket(AF_INET,SOCK_STREAM,0);
    return temp;

}

//自定义初始化ip结构体的函数
//参数一:指向将被初始化的ip结构体的指针
//参数二:具体的IP,例如:192.167.6.5
//参数三:通信端口,HTTP通信应传入80
void init_ip(ip *httpip,char *Ip,int port)
{
    memset(httpip,0,sizeof(*httpip));
    httpip->sin_family=AF_INET;
    httpip->sin_addr.s_addr=inet_addr(Ip);
    httpip->sin_port=htons(port);
}

//自定义将socket和IP绑定的函数
//参数一:socket嵌套字
//参数二:已经指向已经初始化了的ip结构体的指针
//返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中
int Bind(int socket,ip *httpip)
{
    int ret;
    ret=bind(socket,(IP)httpip,sizeof(httpip));
    return ret;
}

//自定义通过accept阻塞等待其他socket对其进行连接的函数
//参数一:要被阻塞的socket嵌套字
//返回值:有其他socket连接到被阻塞的socket则返回和被阻塞的socket进行通信的另一socket嵌套字
int get_other_socket(int socket)
{
    ip otherip;
    int temp;
    socklen_t length;
    length=sizeof(otherip);
    temp=accept(socket,(IP)&otherip,&length);
    return temp;

}


//自定义connect函数
//参数一:客户端自己的socket
//参数二:指向将被连接的IP结构体的指针
//返回值:成功则返回0, 失败返回-1, 错误原因存于errno 中
int Connect(int socket,ip* httpip)
{
    int flag;
    flag=connect(socket,(IP)httpip,sizeof(*httpip));
    return flag;
}


//自定义Send函数
//参数一:自己程序的socket
//参数二:将要发送的数据
//返回值:大于或等于零表示发送了部分或是全部的数据,失败返回-1, 错误原因存于errno 中
//待修改:由于write函数一次可能写不完,所以可能需要修改函数进行多次发送???????????????????如果我没有修改,请后来的勇者继续修改
int Send(int socket,char *Data)
{
    int ret=1;
/*    int sendLength=0,dataLength=0;

    while(ret!=0)
    {}
*/

    ret=write(socket,Data,strlen(Data));
    return ret;
}

//自定义Read函数
//参数一:自己程序的socket
//返回值:成功返回指向存储有相应内容的动态内存的指针,失败返回NULL
//注意:1)返回的动态内存指针在不使用的时候应该通过free释放;2)如果不是真的有问题,请不要动,如果读取数据出现问题,请优先检查data2.c中的函数
char* Read(int socket)
{
    int length=0,return_length;
    char buffer[1024];
    char *Data;
    PBUFFER header,nowBuffer;//nowBuffer指向正在使用的BUFFER节点


    if(NULL!=(header=create_EmptyBufferLink()))//创建BUFFER表头
    {
        if(NULL==(nowBuffer=append_Buffer_Node(header)))//创建第一个存储响应的BUFFER节点
        {
            printf("\nappend_Buffer_Node() fail in http.c Read()\n");//节点添加失败直接返回
            free_Buffer_Link(header);
            return NULL;
        }

    }else
    {
        printf("\ncreate_EmptyBufferLink() fail in http.c Read()\n");//头结点创建失败直接返回
        return NULL;
    }

     //每次读取1024个节点存储到buffer中,然后再通过strncpy复制到BUFFER节点当中
    while((return_length=read(socket,buffer,1024))>0)
    {
        if(return_length==-1)
        {
            printf("\nreceive wrong!\n");
            free_Buffer_Link(header);
            header=NULL;
            return NULL;
        }else
        {

            if(length>=50176)//如果节点已经快要存满,则新建节点,将相应内容存到新建立的节点当中
            {
                nowBuffer->data[length]=‘\0‘;
                if(NULL==(nowBuffer=append_Buffer_Node(header)))
                {
                    printf("\nappend_Buffer_Node() fail in http.c Read()\n");//节点添加失败直接返回
                    free_Buffer_Link(header);
                    return NULL;
                }
                length=0;
                strncpy(nowBuffer->data+length,buffer,return_length);
                length+=return_length;
            }
            else
            {
                strncpy(nowBuffer->data+length,buffer,return_length);
                length+=return_length;
            }
        }

    }

    nowBuffer->data[length]=‘\0‘;
    Data=get_All_Buffer(header);//将BUFFER链表中的内容取出,存储到动态内存当中

     //释放BUFFER链表
     if(header!=NULL)
    {
        free_Buffer_Link(header);
        header=NULL;
    }

    if(length==0)
    {
       printf("no date receive!\n");
        return NULL;
    }

    return Data;//返回指向存储有响应内容的动态内存的指针(可能为空)
}

//进行HTTP通信
//参数一:要进行HTTP通信的IP,如192.168.6.1
//参数二:发送给HTTP服务端的数据
//参数三:指向存储HTTP响应内容指针的变量的指针,如不明白,可参考动态内存在函数间的传递
//返回值:成功返回1,失败返回0
//注意:动态内存必须释放
int http_perform(char *Ip,char *DataSend,char **buffer)
{

    int client_socket_word;
    ip httpip;

    if(-1==(client_socket_word=create_socket()))
    {
        perror("http.c create_socket() fail");
        return 0;
    }


    init_ip(&httpip,Ip,80);

    if(-1==Connect(client_socket_word,&httpip))
    {
        perror("http.c Connect() fail");
        return 0;
    }


    if(-1==Send(client_socket_word,DataSend))
    {
        perror("http.c Send() fail");
        return 0;
    }


    *buffer=Read(client_socket_word);

    if(NULL==buffer)
    {
        perror("http.c Read() fail");
        return 0;
    }

    if(-1!=client_socket_word)
    {
        close(client_socket_word);
        return 1;
    }

    return 0;
}

//通过结构体URL进行HTTP通信
//参数一:存储有通信信息的结构体
//参数二:指向存储HTTP响应的动态指针的地址,使用完之后必须释放,使用之前必须检查BUFFER是否为NULL(即使is_respond_ok()失败,动态内存中依旧可能存储有响应失败的信息)
//返回值:成功返回1,失败返回0
//注意:无论成功或是失败,动态内存真的必须释放!!!
int http_perform_url(PURL url,char **Buffer)
{
    char host[100];
    char path[500];
    char request[10*1024];//差点忘了你

    memset(request,‘\0‘,10*1024*sizeof(char));

    if(1==http_request(request,url))
    {
        if(1==parse_url(host,path,url->url))
        {

            if(1==http_perform(host,request,Buffer))
            {
                if(NULL!=Buffer)
                {
                    if(1==is_respond_ok(*Buffer))
                    {
                        return 1;
                    }
                }
            }


        }
    }

    return 0;
}

//截取两个指针之间的字符串
//参数一:字符串开始的指针
//参数二:字符串结束的指针
//返回值:成功返回1,失败返回0
int str_between(char* result,char *pStart,char *pEnd)
{
    char *result_,*pStart_;
    result_=result;
    pStart_=pStart;

    if((pStart)&&(pEnd)&&(pEnd>pStart))
    {
        while((pStart_)!=pEnd)
        {
            *(result_)=*(pStart_);
            pStart_++;
            result_++;

        }
    }else
    {
        return 0;
    }
    *(result_)=‘\0‘;
    return 1;
}

//从HTTP响应当中寻找COOKIE
//参数一:存储COOKIE字符串的指针
//参数二:存储有COOKIE的HTTPBUFFER
int find_cookie(char *Cookie,char *httpBuffer)
{
    char *pStart,*pEnd,*temp;
    if((strstr(httpBuffer,SETCOOKIE)!=NULL))
    {
        temp=strstr(httpBuffer,SETCOOKIE);
        pStart=temp+sizeof(SETCOOKIE);
        pStart--;
    }

    if((temp=strstr(httpBuffer,"; path"))!=NULL)
    {
        pEnd=temp;
    }

    if(!((pStart)&&(pEnd)))
    {
        return 0;
    }

    if(str_between(Cookie,pStart,pEnd))
    {
        printf("%s\n",Cookie);
        return 1;
    }
    else
    {
        return 0;
    }

}

//当想要自己设置cookie,可以通过这个函数将自定义的cookie复制到全局变量当中
//参数一:cookie字符串,如:“synsnd=hdh38rhy3gdyug873gdyguwsgdipo39yrdh”
void Set_Cookie(char *cookie_)
{
    if(cookie_)
    {
        strcpy(cookie,cookie_);
    }

}

//通过检查HTTPBUFFER当中是否有“302 Found”和“200 OK”判断响应是否成功
//参数1:HTTPBUFFER
//返回值:成功返回1,失败返回0
int is_respond_ok(char *httpBuffer)
{
    if((strstr(httpBuffer,"302 Found"))||(strstr(httpBuffer,"200 OK")))
    {
        printf("Respond ok!\n");
        return 1;
    }
    else
    {
        printf("Respond wrong!\n");
        return 0;

    }
}

//产生长度大概为16-19的随机数字字符串
//参数一:用于存储随机数字字符串的字符串指针
//待修改:我没有设定返回值和纠错机制,只要用足够大的字符串去接受的话,一般不会出错
void randomCode(char *result)
{
    int i;
    char temp1[20],temp2[20];
    srand((unsigned int)time(NULL));
    i=rand();
    num_to_string(temp1,i);
    i=rand();
    num_to_string(temp2,i);

    strcpy(result,temp1);
    strcat(result,temp2);
}

//当HTTP响应不为空,用以释放存储响应的动态内存
void httpBuffer_free(char **respond)
{
    if(*respond!=NULL)
    {
        free(*respond);
        *respond=NULL;//应该为*respond=NULL而不是respond=NULL,改变的是respond中存储的指针
    }
}

 

下一篇放使用例子。

 
























































































































































































































































































































































































































以上是关于linux c使用socket进行http 通信,并接收任意大小的http响应的主要内容,如果未能解决你的问题,请参考以下文章

C/C++ socket编程教程:1天玩转socket通信技术

提高 Linux 上 socket 性能

linux用java socket与c的socket通信乱码问题

C++ socket编程 和 MFC socket编程 有啥区别??

Linux进程间通信 -- 数据报套接字 socket()bind()sendto()recvfrom()close()

linux下C++ socket网络编程——即时通信系统(含源码)