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响应(四)的更多相关文章
- linux c使用socket进行http 通信,并接收任意大小的http响应(三)
使用socket进行http通信的时候,浏览器返回的响应经常不是固定长度的,有时候很大,有些时候又非常小,十分讨厌.如果仅仅只是为了接收一小段信息,设置一个十分大的缓存,这样又会十分浪费.而且经常更改 ...
- linux c使用socket进行http 通信,并接收任意大小的http响应(二)
先贴请求头部信息组织代码. 有同学会疑问http_url.h是干什么用的,我要在这里声明,http_url.h并不是给http_url.c用的,实际上http_url.h声明了http_url.c已经 ...
- linux c使用socket进行http 通信,并接收任意大小的http响应(一)
如何进行http通信呢?我们打开任意一个浏览器,按F12,再选择网络,然后打开任意一个网站,我们就可以看到浏览器和网站通信的过程 如下图: 然后,我们任意点击一条记录,可以看到 然后,查找http协议 ...
- linux c使用socket进行http 通信,并接收任意大小的http响应(五)
http.c data2.c http_url.c http.h data2.h http_url.h主要实现的功能是通过URL结构体来实现HTTP通信,你可以把这三个文件独立出来,作为HTTP通信模 ...
- c++ 网络编程(一)TCP/UDP windows/linux 下入门级socket通信 客户端与服务端交互代码
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9601511.html c++ 网络编程(一)TCP/UDP 入门级客户端与服务端交互代码 网 ...
- 基于ARM9和嵌入式Linux系统的多功能综合通信控制系统的框架
基于ARM9硬件平台和嵌入式Linux系统的多功能综合通信控制系统的框架设计及各模块的功能.系统采用符合POSIX.1标准的C语言编写,实现了对下位机传送数据帧的采集.分析和存储,并能根据上位机的配置 ...
- LINUX 下 ipv6 socket 编程
大家都知道,随着互联网上主机数量的增多,现有的32位IP地址已经不够用了,所以推出了下一代IP地址IPv6,写网络程序的要稍微改变一下现有的网络程序适应IPv6网络是相当容易的事.对于我们来说就是IP ...
- linux各种IPC机制(进程通信)
linux各种IPC机制 (2011-07-08 16:58:35) 原文地址:linux各种IPC机制(转)作者:jianpengliu 原帖发表在IBM的developerworks网站 ...
- Linux学习之socket编程(二)
Linux学习之socket编程(二) 1.C/S模型——UDP UDP处理模型 由于UDP不需要维护连接,程序逻辑简单了很多,但是UDP协议是不可靠的,实际上有很多保证通讯可靠性的机制需要在应用层实 ...
随机推荐
- 1*1的卷积核与Inception
https://www.zhihu.com/question/56024942 https://blog.csdn.net/a1154761720/article/details/53411365 本 ...
- 转——git常见使用命令及git原理
0.常用命令1 1.git中brunch的使用和理解(一定理解brunch的指针理解和分叉) 分支创建 Git 是怎么创建新分支的呢? 很简单,它只是为你创建了一个可以移动的新的指针. 比如,创建一个 ...
- 关于使用MUI框架ashx获取值的问题
前台如有 var value = '<%= value%>'; 后台在使用 Params["value"]的时候会出现重复(例:value,value).
- PHP保留两位小数并且四舍五入及不四舍五入的方法
php保留两位小数并且四舍五入 $num = 123213.666666; echo sprintf("%.2f", $num); php保留两位小数并且不四舍五入 $num = ...
- Linux下按扇区读写块设备
本文介绍Linux下按扇区读写块设备(示例TF卡),实际应用是在Android系统上,主要方法如下: 1.找到sdcard的挂载点,在android2.1系统下应该为/dev/block/mmcblk ...
- day05数据类型,数字类型,字符串类型,字符串的操作方法,列表类型的操作方法,可变类型与不可变类型
复习 ''' 流程控制 1.顺序结构.分支结构.循环结构 2.if分支结构 if 条件: 代码块 elif 条件: 代码块 else: 代码块 # 可以被if转换为False:0 | '' | Non ...
- 学习了一天的python,终于可以爬爬了-_-
恒久恒久以前在语言大陆就听过一种叫,人生苦短,我用python的至理名言.陆陆续续在课下和业余生活中学习的一点python,知道基本的语法和规则,不过py的库实在是太多了,而且许多概念也没有深入的学习 ...
- 使用JS调用手机本地摄像头或者相册图片识别二维码/条形码
接着昨天的需求,不过这次不依赖微信,使用纯js唤醒手机本地摄像头或者选择手机相册图片,识别其中的二维码或者是条形码.昨天,我使用微信扫一扫识别,效果超棒的.不过如果依赖微信的话,又怎么实现呢,这里介绍 ...
- ipan笔记
// 对于mysql来说, 如果字段没有设置其 default值, 则会自动 设置 default值为null.同理没有设置not null, 则会自动允许null =yes // create ta ...
- Learning-Python【12】:装饰器
一.什么是装饰器 器:工具 装饰:为被装饰对象添加新功能 装饰器本身可以是任意可调用的对象,即函数 被装饰的对象也可以是任意可调用的对象,也是函数 目标:写一个函数来为另外一个函数添加新功能 二.为何 ...