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中存儲的指針
    }
}

 

下一篇放使用例子。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM