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中存储的指针
    }
}

下一篇放使用例子。

时间: 2024-10-07 15:28:42

linux c使用socket进行http 通信,并接收任意大小的http响应(四)的相关文章

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

使用socket进行http通信的时候,浏览器返回的响应经常不是固定长度的,有时候很大,有些时候又非常小,十分讨厌.如果仅仅只是为了接收一小段信息,设置一个十分大的缓存,这样又会十分浪费.而且经常更改缓存大小的话,也不太好. 为了能够接收任意大小的响应,我程序的流程大概是这样子的: (1)将SOCKET接收的信息保存到一个动态分配内存的链表里.链表每个节点存储有固定字节大小的HTTP响应,每当一个节点存储满,就继续添加一个新的节点继续缓存: (2)接收信息结束后,将存储在链表当中的HTTP响应全

C语言 linux环境基于socket的简易即时通信程序

转载请注明出处:http://www.cnblogs.com/kevince/p/3891033.html   By Kevince 最近在看linux网络编程相关,现学现卖,就写了一个简易的C/S即时通信程序,代码如下: head.h 1 /*头文件,client和server编译时都需要使用*/ 2 #include <unistd.h> 3 #include <stdio.h> 4 #include <sys/types.h> 5 #include <sys

linux各种IPC机制(进程通信)

linux各种IPC机制 (2011-07-08 16:58:35)     原文地址:linux各种IPC机制(转)作者:jianpengliu 原帖发表在IBM的developerworks网站上,是一个系列的文章,作者郑彦兴,通过讲解和例子演示了Linux中几种IPC的使用方式,我觉得很好,在这里做一个保留,能看完的话Linux IPC的基础是没有问题的了.一)Linux环境进程间通信(一)管道及有名管道http://www.ibm.com/developerworks/cn/linux/

基于Linux C的socket抓包程序和Package分析 (一)

 测试运行平台:CentOS 6.5发行版,内核版本3.11 1. Linux抓包源程序 在OSI七层模型中,网卡工作在物理层和数据链路层的MAC子层. 进行网络通信时,源主机通过socket(或其它)应用程序产生IP报文,经过各个OSI层层封装,数据包以Ethernet帧的形式进入物理层.Ethernet帧包含源主机地址.IP报文.目标地址(IP地址.端口号或映射的6字节MAC地址)和需要传送到目标主机的其它信息. 目标的MAC地址是哪里来的呢?这牵扯到一个ARP协议(介乎于网络层和数据链

Linux系统编程札记:进程通信(一) &nbsp; &nbsp;

进程简单来讲就是一个程序的一次执行,这里说的进程一般都指的是运行在用户态的进程,而处于用户态的不同进程之间是彼此相互隔离的,它们必须通过某种方式来进行通信,具体理由如下: (1)数据传输:有时候一个进程需要将它的数据发送给另一个进程. (2)资源共享:有时候多个进程之间需要共享同样的资源. (3)通知事件:有时候一个进程需要向另一个或一组进程发送消息,通知它们发生了某个事件. (4)进程控制:有些进程希望能够完全控制另一个进程的执行,此时控制进程希望能够拦截另一进程的所有操作,并能够及时知道它的

Linux下的socket网络编程

linux 网络编程是通过socket(套接字)接口实现,Socket是一种文件描述符,socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种"打开-读/写-关闭"模式的实现,服务器和客户端各自维护一个"文件",在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件. socket 类型 常见的socket有3种类型如下.     (1)流式socket(SOCK_STREAM )     流式套接字提供可靠

LINUX 下 ipv6 socket 编程

大家都知道,随着互联网上主机数量的增多,现有的32位IP地址已经不够用了,所以推出了下一代IP地址IPv6,写网络程序的要稍微改变一下现有的网络程序适应IPv6网络是相当容易的事.对于我们来说就是IP地址变化了,所以程序里在用到IP地址的地方做相应的改变就可以了. 记住:主要是改变程序里设置IP地址和端口等部分的代码. 服务器端源代码如下:/***********************/#include <stdio.h>#include <stdlib.h>#include &

Flex Socket与Java通信实例说明(转)

Flex Socket与Java通信实例说明(转) 这两天一直在flex的Socket ,现在终于懂了很多.由浅到深一步一步深入.慢慢体会实例,虽然实例都是在网上找的,但也经过了我的测试.我比较喜欢注释,也注释了很多. 跟着走你就会懂.. Flex端 和 Java端, 先运行Java端启动服务.然后在测试Flex. 实例一: Flex端: <?xml version="1.0" encoding="utf-8"?> <mx:TitleWindow

Windows 和 Linux下使用socket下载网页页面内容(可设置接收/发送超时)的代码

主要难点在于设置recv()与send()的超时时间,具体要注意的事项,请看代码注释部分,下面是代码: [cpp] view plaincopyprint? #include <stdio.h> #include <sys/types.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <string.h> #ifdef _WIN32   ///