终于说到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中存储的指针
}
}
下一篇放使用例子。