需要在开发板上实现以http的协议上传图片的功能。


参考了以下作者的文章:

http://www.cnblogs.com/linbc/archive/2009/03/21/1400108.html

http://blog.csdn.net/sjin_1314/article/details/41776679

http://www.xuebuyuan.com/989667.html

http://blog.csdn.net/chinazgr/article/details/8244840


以及:

https://www.ietf.org/rfc/rfc1867.txt对于multipart/form-data的说明案例:

6. Examples

   Suppose the server supplies the following HTML:

     <FORM ACTION="http://server.dom/cgi/handle"
           ENCTYPE="multipart/form-data"
           METHOD=POST>
     What is your name? <INPUT TYPE=TEXT NAME=submitter>
     What files are you sending? <INPUT TYPE=FILE NAME=pics>
     </FORM>

   and the user types "Joe Blow" in the name field, and selects a text
   file "file1.txt" for the answer to 'What files are you sending?'

   The client might send back the following data:

        Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"; filename="file1.txt"
        Content-Type: text/plain

         ... contents of file1.txt ...
        --AaB03x--

   If the user also indicated an image file "file2.gif" for the answer
   to 'What files are you sending?', the client might client might send
   back the following data:

        Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"
        Content-type: multipart/mixed, boundary=BbC04y

        --BbC04y
        Content-disposition: attachment; filename="file1.txt"
        Content-Type: text/plain

        ... contents of file1.txt ...
        --BbC04y
        Content-disposition: attachment; filename="file2.gif"
        Content-type: image/gif
        Content-Transfer-Encoding: binary

          ...contents of file2.gif...
        --BbC04y--
        --AaB03x--


其中对于http://www.cnblogs.com/linbc/archive/2009/03/21/1400108.html文章里的代码我基本上全拿过来用了,谢谢原作者!


文件如下:

tuobao_tcpclient.h

#ifndef _TUOBAO_TCP_CLIENT_
#define _TUOBAO_TCP_CLIENT_

#include <netinet/in.h>
#include <sys/socket.h>

typedef struct _tuobao_tcpclient{
    int socket;
    int remote_port;
    char remote_ip[16];
    struct sockaddr_in _addr;
    int connected;
} tuobao_tcpclient;

int tuobao_tcpclient_create(tuobao_tcpclient *,const char *host, int port);
int tuobao_tcpclient_conn(tuobao_tcpclient *);
int tuobao_tcpclient_recv(tuobao_tcpclient *,char **lpbuff,int size);
int tuobao_tcpclient_send(tuobao_tcpclient *,char *buff,int size);
int tuobao_tcpclient_close(tuobao_tcpclient *);

#endif



tuobao_tcpclient.c

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>

#include "tuobao_tcpclient.h"

#define BUFFER_SIZE 1024


int tuobao_tcpclient_create(tuobao_tcpclient *pclient,const char *host, int port){
    struct hostent *he;

    if(pclient == NULL) return -1;
    memset(pclient,0,sizeof(tuobao_tcpclient));

    if((he = gethostbyname(host))==NULL){
        return -2;
    }

    pclient->remote_port = port;
    strcpy(pclient->remote_ip,inet_ntoa( *((struct in_addr *)he->h_addr) ));

    pclient->_addr.sin_family = AF_INET;
    pclient->_addr.sin_port = htons(pclient->remote_port);
    pclient->_addr.sin_addr = *((struct in_addr *)he->h_addr);

    if((pclient->socket = socket(AF_INET,SOCK_STREAM,0))==-1){
        return -3;
    }

    /*TODO:是否应该释放内存呢?*/

    return 0;
}

int tuobao_tcpclient_conn(tuobao_tcpclient *pclient){
    if(pclient->connected)
        return 1;

    if(connect(pclient->socket, (struct sockaddr *)&pclient->_addr,sizeof(struct sockaddr))==-1){
        return -1;
    }

    pclient->connected = 1;

    return 0;
}

int tuobao_tcpclient_recv(tuobao_tcpclient *pclient,char **lpbuff,int size){
    int recvnum=0,tmpres=0;
    char buff[BUFFER_SIZE];

    *lpbuff = NULL;

    while(recvnum < size || size==0){
        tmpres = recv(pclient->socket, buff,BUFFER_SIZE,0);
        if(tmpres <= 0)
            break;
        recvnum += tmpres;

        if(*lpbuff == NULL){
            *lpbuff = (char*)malloc(recvnum);
            if(*lpbuff == NULL)
                return -2;
        }else{
            *lpbuff = (char*)realloc(*lpbuff,recvnum);
            if(*lpbuff == NULL)
                return -2;
        }

        memcpy(*lpbuff+recvnum-tmpres,buff,tmpres);
    }

    return recvnum;
}

int tuobao_tcpclient_send(tuobao_tcpclient *pclient,char *buff,int size){
    int sent=0,tmpres=0;

    while(sent < size){
        tmpres = send(pclient->socket,buff+sent,size-sent,0);
        if(tmpres == -1){
            return -1;
        }
        sent += tmpres;
    }
    return sent;
}

int tuobao_tcpclient_close(tuobao_tcpclient *pclient){
    close(pclient->socket);
    pclient->connected = 0;
}


httppost.c

#include "tuobao_tcpclient.h"
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>

void http_post_file(tuobao_tcpclient *pclient,char *page,char *filepath,char **response){

	//check if the file is valid or not
	struct stat stat_buf;
	if(lstat(filepath,&stat_buf)<0){
		printf("lstat %s fail\n");
		return;
	}
	if(!S_ISREG(stat_buf.st_mode)){
		printf("%s is not a regular file!\n",filepath);
		return ;
	}

	char *filename;
	filename=strrchr(filepath,'/');
	if(filename==NULL){

	}
	filename+=1;
	if(filename>=filepath+strlen(filepath)){
		//'/' is the last character
		printf("%s is not a correct file!\n",filepath);
		return ;
	}

	printf("filepath=%s,filename=%s\n",filepath,filename);

	char content_type[2048];
	memset(content_type, 0, 2048);

	char post[300],host[100],content_len[100];
	char *lpbuf,*ptmp;
	int len=0;

	lpbuf = NULL;
	const char *header2="User-Agent: Is Http 1.1\r\nCache-Control: no-cache\r\nAccept: */*\r\n";

	sprintf(post,"POST %s HTTP/1.1\r\n",page);
	sprintf(host,"HOST: %s:%d\r\n",pclient->remote_ip,pclient->remote_port);

	strcpy(content_type,post);
	strcat(content_type,host);


	char *boundary = (char *)"---------------------------41184676334";


	strcat(content_type, "Content-Type: multipart/form-data; boundary=");
	strcat(content_type, boundary);
	strcat(content_type, "\r\n");

	//--Construct request data {filePath, file}
	char content_before[4096];
	memset(content_before, 0, 4096);
	strcat(content_before, "--");
	strcat(content_before, boundary);
	strcat(content_before, "\r\n");
	strcat(content_before, "Content-Disposition: form-data; name=\"filePath\"\r\n\r\n");
	strcat(content_before, filepath);
	strcat(content_before, "\r\n");
	strcat(content_before, "--");
	strcat(content_before, boundary);
	strcat(content_before, "\r\n");
	strcat(content_before, "Content-Disposition: attachment; name=\"userfile\"; filename=\"");
	strcat(content_before, filename);
	strcat(content_before, "\"\r\n");
	strcat(content_before, "Content-Type: image/jpeg\r\n\r\n");
//	strcat(content_before, "Content-Type: image/jpeg\r\n\r\n");

	char content_end[1024];
	memset(content_end, 0, 1024);
	strcat(content_end, "\r\n");
	strcat(content_end, "--");
	strcat(content_end, boundary);
	strcat(content_end, "--\r\n");

	int max_cont_len=5*1024*1024;
	char content[max_cont_len];
	int fd;
	fd=open(filepath,O_RDONLY,0666);
	if(!fd){
		printf("fail to open file : %s\n",filepath);
		return;
	}
	len=read(fd,content,max_cont_len);
	close(fd);

	char *lenstr;
	lenstr = (char*)malloc(128);
	sprintf(lenstr, "%d", (strlen(content_before)+len+strlen(content_end)));

	strcat(content_type, "Content-Length: ");
	strcat(content_type, lenstr);
	strcat(content_type, "\r\n\r\n");

	//send
	if(!pclient->connected){
		tuobao_tcpclient_conn(pclient);
	}

	//content-type
	tuobao_tcpclient_send(pclient,content_type,strlen(content_type));

	//content-before
	tuobao_tcpclient_send(pclient,content_before,strlen(content_before));

	//content
	tuobao_tcpclient_send(pclient,content,len);

    //content-end
	tuobao_tcpclient_send(pclient,content_end,strlen(content_end));

	/*it's time to recv from server*/
	if(tuobao_tcpclient_recv(pclient,&lpbuf,0) <= 0){
		if(lpbuf) free(lpbuf);
		return -2;
	}
	printf("接收响应:\n%s\n",lpbuf);

	    /*响应代码,|HTTP/1.0 200 OK|
	     *从第10个字符开始,第3位
	     * */
	    memset(post,0,sizeof(post));
	    strncpy(post,lpbuf+9,3);
	    if(atoi(post)!=200){
	        if(lpbuf) free(lpbuf);
	        return atoi(post);
	    }


	    ptmp = (char*)strstr(lpbuf,"\r\n\r\n");
	    if(ptmp == NULL){
	        free(lpbuf);
	        return -3;
	    }
	    ptmp += 4;/*跳过\r\n*/

	    len = strlen(ptmp)+1;
	    *response=(char*)malloc(len);
	    if(*response == NULL){
	        if(lpbuf) free(lpbuf);
	        return -1;
	    }
	    memset(*response,0,len);
	    memcpy(*response,ptmp,len-1);

	    /*从头域找到内容长度,如果没有找到则不处理*/
	    ptmp = (char*)strstr(lpbuf,"Content-Length:");
	    if(ptmp != NULL){
	        char *ptmp2;
	        ptmp += 15;
	        ptmp2 = (char*)strstr(ptmp,"\r\n");
	        if(ptmp2 != NULL){
	            memset(post,0,sizeof(post));
	            strncpy(post,ptmp,ptmp2-ptmp);
	            if(atoi(post)<len)
	                (*response)[atoi(post)] = '\0';
	        }
	    }

	    if(lpbuf) free(lpbuf);

	    return 0;

}

int http_post(tuobao_tcpclient *pclient,char *page,char *request,char **response){

    char post[300],host[100],content_len[100];
    char *lpbuf,*ptmp;
    int len=0;

    lpbuf = NULL;
    const char *header2="User-Agent: Tuobao Http 0.1\r\nCache-Control: no-cache\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: */*\r\n";

    sprintf(post,"POST %s HTTP/1.0\r\n",page);
    sprintf(host,"HOST: %s:%d\r\n",pclient->remote_ip,pclient->remote_port);
    sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(request));

    len = strlen(post)+strlen(host)+strlen(header2)+strlen(content_len)+strlen(request)+1;
    lpbuf = (char*)malloc(len);
    if(lpbuf==NULL){
        return -1;
    }

    strcpy(lpbuf,post);
    strcat(lpbuf,host);
    strcat(lpbuf,header2);
    strcat(lpbuf,content_len);
    strcat(lpbuf,request);

    if(!pclient->connected){
        tuobao_tcpclient_conn(pclient);
    }

    if(tuobao_tcpclient_send(pclient,lpbuf,len)<0){
        return -1;
    }
printf("发送请求:\n%s\n",lpbuf);

    /*释放内存*/
    if(lpbuf != NULL) free(lpbuf);
    lpbuf = NULL;

    /*it's time to recv from server*/
    if(tuobao_tcpclient_recv(pclient,&lpbuf,0) <= 0){
        if(lpbuf) free(lpbuf);
        return -2;
    }
printf("接收响应:\n%s\n",lpbuf);

    /*响应代码,|HTTP/1.0 200 OK|
     *从第10个字符开始,第3位
     * */
    memset(post,0,sizeof(post));
    strncpy(post,lpbuf+9,3);
    if(atoi(post)!=200){
        if(lpbuf) free(lpbuf);
        return atoi(post);
    }


    ptmp = (char*)strstr(lpbuf,"\r\n\r\n");
    if(ptmp == NULL){
        free(lpbuf);
        return -3;
    }
    ptmp += 4;/*跳过\r\n*/

    len = strlen(ptmp)+1;
    *response=(char*)malloc(len);
    if(*response == NULL){
        if(lpbuf) free(lpbuf);
        return -1;
    }
    memset(*response,0,len);
    memcpy(*response,ptmp,len-1);

    /*从头域找到内容长度,如果没有找到则不处理*/
    ptmp = (char*)strstr(lpbuf,"Content-Length:");
    if(ptmp != NULL){
        char *ptmp2;
        ptmp += 15;
        ptmp2 = (char*)strstr(ptmp,"\r\n");
        if(ptmp2 != NULL){
            memset(post,0,sizeof(post));
            strncpy(post,ptmp,ptmp2-ptmp);
            if(atoi(post)<len)
                (*response)[atoi(post)] = '\0';
        }
    }

    if(lpbuf) free(lpbuf);

    return 0;
}

int main(){

    tuobao_tcpclient client;

    char *response = NULL;
    printf("开始组包\n");
    tuobao_tcpclient_create(&client,"127.0.0.1",80);

//    if(http_post(&client,"/recv_file.php","f1=hello",&response)){
//        printf("失败!\n");
//        exit(2);
//    }
    http_post_file(&client,"/recv_file.php","/home/gumh/time_1970_186.jpg",&response);

    printf("响应:\n%d:%s\n",strlen(response),response);

    free(response);
    return 0;
}






Logo

更多推荐