嵌入式在线商城

一、主线功能

1、设计与实现在线商城系统涉及到前端展示、后台管理以及数据库进行查找,功能包含登录页面、商品搜素、商品详细信息查找。

二、页面设计

2.1、商品搜索设计

2.2、商品详细信息展示设计

2.3、TCP并发服务器设计

HTTP是基于Tcp服务器搭建起来的

第一步,建立连接

cs 复制代码
//创建套接字并且监听 
int create_sever(const char *ip ,unsigned short port)
{	
    int option,optlen;
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (-1 == sockfd)
	{
		perror("fail socket");
		return -1;
    }
    optlen=sizeof(option);
    option=1;
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void*)&option,optlen);
    struct sockaddr_in ser;
	ser.sin_family = AF_INET;
	ser.sin_port = htons(port);
	ser.sin_addr.s_addr = inet_addr(ip);
	int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));
	if (-1 == ret)
	{
		perror("fail bind");
		return -1;
	}
	ret = listen(sockfd, 128);
	if (-1 == ret)
	{
		perror("fail listen");
		return -1;
	}
	
	return sockfd;
}

第二步、接收监听队列里面的套接字,并产生通信的套接字

cs 复制代码
  int connfd = accept(sockfd, NULL, NULL);
		if (-1 == connfd)
                {
                    perror("fail accept");
                    continnue;
}

至此三次握手建立完毕

第三步、接收网页传过来的HTTP报文

cs 复制代码
//接收报文
int recv_http_request(int connfd,char *http_req,int maxlen)
{
    memset(http_req,0,maxlen);
    ssize_t size = recv(connfd,http_req,maxlen,0);
    if(size <= 0)
    {
        perror("fail1 recv");
        return size;
    }
    return size;
}
//将接收的内容进行解析,解析分为三步,方法、url、内容
int parse_http_request(char *http_req,HTTP_REQ_t *phttp)
{
    char buf[256] = {0};

    memset(phttp,0,sizeof(HTTP_REQ_t));
    char *p = strtok(http_req," ");
    if(NULL == p)
    {
        return -1;
    }
    strcpy(phttp->method,p);
    p = strtok(NULL," ");
    if(NULL == p)
    {
        return -1;
    }
    strcpy(phttp->url,p);
    p = strtok(NULL,"\0");
    if(NULL == p)
    {
        return -1;
    }
    p = strstr(p,"\r\n\r\n");
    if(NULL == p)
    {
        return -1;
    }
    strcpy(phttp->content,p+4);
    parse_phttp(phttp->content,buf);
    strcpy(phttp->content,buf);
    printf("--->%s\n",phttp->content);
    return 0;

}

第四步、对接收的报文需要的内容,进行发送

cs 复制代码
//先发送报文的头部
int send_http_head(int connfd)
{
    char *head ="HTTP/1.1 200 OK\r\n"
                "Content-Type: text/html; charset=utf-8\r\n"
                "Sever: my-web-sever\r\n"
                "Connection: keep-alive\r\n\r\n";
    ssize_t size = send(connfd,head,strlen(head),0);
    if(size < 0)
    {
        perror("fail send");
        return -1;
    }
    return 0;
}
//打开需要的文件的资源,并将该资源进行发送
int send_http_file(int connfd,char *filename)
{
    char buf[1024] = {0};
    int fd = open(filename,O_RDONLY);
    if(fd < 0)
    {
        perror("fail open file");
        return -1;
    }
    while(1)
    {
        ssize_t size = read(fd,buf,sizeof(buf));
        if(size <= 0)
        {
            break;
        }
        send(connfd,buf,size,0);
    }
    close(fd);
    return 0;
}
//发送响应请求
int send_http_reponse(int connfd,HTTP_REQ_t *phttp)
{
    char *p;
    int i = 0;
    char sfile[1024] = {0};
    send_http_head(connfd);
    char *q;
    p = strtok(phttp->url,"?");
    q = strtok(NULL,"\0");
    printf("%s",phttp->url);
    if(!strcmp(phttp->method,"GET"))//请求方法
    {
        if(!strcmp(phttp->url,"/"))
        {
            sprintf(sfile,"./res/denglu.html");
            send_http_file(connfd,sfile);
            return 0;
        }
        else if(strstr(phttp->url,".jpg") || strstr(phttp->url,".png"))
        {
            if(strstr(phttp->url,"200905"))
            {
                sprintf(sfile,".%s",phttp->url);
                send_http_file(connfd,sfile);
            }
            else
            {
                sprintf(sfile,"./res%s",phttp->url);
                send_http_file(connfd,sfile);
            }

            return 0;
        }
        else if(strstr(phttp->url,"/favicon.ico"))//图标
        {
            return 0;
        }
        else if(strstr(phttp->url,".html"))
        {
            if(strcmp(phttp->url,"/4.html")==0)//特殊的,四级页面,我们根据请求直接将网页的标签内容在此写好进行发送
            {
                sprintf(sfile,"./res%s",phttp->url);
                send_http_file(connfd,sfile);
                record = connfd;
                char *site = index(q,'='); 
                select_sqlite4(site+1);
                char buf[100] = "<body><html>";
                send(connfd,buf,strlen(buf),0);
            }
            else
            {
                sprintf(sfile,"./res%s",phttp->url);
                send_http_file(connfd,sfile);
            }
        }
    }
    else if(!strcmp(phttp->method,"POST"))
    {
        if(strstr(phttp->url,".html"))
        {
            if(strcmp(phttp->url,"/meaning.html") == 0)
            {
                sprintf(sfile,"./res%s",phttp->url);//与上述想法同理
                send_http_file(connfd,sfile);
                printf("sendfile = %s\n",sfile);
                record = connfd;
                select_sqlite(phttp->content);
                char buf[100] = "<body><html>";
                send(connfd,buf,strlen(buf),0);
                return 0;
            }
            sprintf(sfile,"./res%s",phttp->url);
            send_http_file(connfd,sfile);
            printf("sendfile = %s\n",sfile);
            return 0;
        }
    }
}

三、函数端口

|---------------------------------------------------------------------------------|----------------------|-----|-------------|
| 接口 | 参数 | 返回值 | 接口描述 |
| Intcallback(void*arg,intcolumn_cnt,char **column_value,char **column_name) | 查到数据列数,地址集合,每一列列名的集合 | 0 | 回调函数 |
| int select_sqlite(char *p) | 数据库指针 | fd | 数据库查找 |
| int create_sever(constchar*ip ,unsigned short port) | 地址,端口 | 0 | 创造数据服务器端口号 |
| int epoll_del_fd(int epfds,int fd) | 文件描述符集合句柄,端口 | 0 | 删除文件描述符,从数组 |
| int epoll_add_fd(int epfds,int fd,uint32_t event) | 文件描述符集合句柄,端口 | 0 | 未来世界 |
| intrecv_http_request(intconnfd,char *http_req,int maxlen) | 文件描述符,结构体指针,最大长度 | 0 | 接受TCP报文请求 |
| intparse_http_request(char*http_req,HTTP_REQ_t *phttp) | 结构体对象指针,请求对象 | 0 | 对请求报文进行解析 |
| int send_http_head(int connfd) | 文件描述符 | 0 | 发送报文的头部 |
| int send_http_file(int connfd,char *filename) | 文件描述符,文件 | 0 | 发送报文想要的内容 |
| intsend_http_reponse(intconnfd,HTTP_REQ_t *phttp) | 文件描述符,结构体对象 | 0 | 发生报文进行服务器响应 |

四、并发服务器的设计

4.1、并发设计

主要用的是IO多路复用的epoll 进行设计,其资源消耗相对来说比较小,对于小型网页来说,完全够用,且效率高

4.2、设计过程

第一步、将创建好的套接字的文件描述添加到数组里面

第二步、遍历数组、查找当前的套接字

第三步、执行当前套接字所需运行的内容

cs 复制代码
//主函数 ,并发服务器
int main(int agrc,char *agrv[])
{
    int connfd = 0;
    char buf[1024] = {0};
    HTTP_REQ_t http;
    char http_req[4096] = {0};
    int ret = 0;
    int sockfd = create_sever("192.168.208.85",8080);
    if(sockfd == -1)
    {
        perror("fail socket");
        return -1;
    }
    int epfds = epoll_create(1024);
    if(-1 == epfds)
    {
        perror("fail epoll_create");
        return -1;
    }
    epoll_add_fd(epfds,sockfd,EPOLLIN);
    struct epoll_event evs[1024];
    while(1)
    {
        int cnt = epoll_wait(epfds,evs,1024,-1);
        if(cnt < 0)
        {
            perror("fail epoll_wait");
            return -1;
        }
        for(int i=0;i<cnt;i++)
        {
            if(sockfd == evs[i].data.fd)
            {
                int connfd = accept(sockfd, NULL, NULL);
		if (-1 == connfd)
                {
                    perror("fail accept");
                    continue;
                }
                epoll_add_fd(epfds, connfd, EPOLLIN);
            }
            else
            {
                memset(http_req,0,sizeof(http_req));
                recv_http_request(evs[i].data.fd,http_req,sizeof(http_req));
                printf("----------\n%s\n----------\n",http_req);
                ret = parse_http_request(http_req,&http);
                if(ret < 0)
                {
                    close(evs[i].data.fd);
                    continue;
                }
                printf("method : %s\n",http.method);
                printf("url    : %s\n",http.url);
                printf("content: %s\n",http.content);
                printf("----------------------------\n");
                int size = send_http_reponse(evs[i].data.fd,&http);
                if(size < 0)
                {
                    perror("fail2 recv");
                    epoll_del_fd(epfds,evs[i].data.fd);
                    close(evs[i].data.fd);
                    continue;
                }
                close(evs[i].data.fd);
            }
        }
    }
    return 0;
}


//增加此刻的文件描述符到数组中
int epoll_add_fd(int epfds,int fd,uint32_t event)
{
    struct epoll_event ev;
    ev.events = event;
    ev.data.fd = fd;
    int ret = epoll_ctl(epfds,EPOLL_CTL_ADD,fd,&ev);
    if(-1 == ret)
    {
        perror("fail epoll_ctl add");
        return -1;
    }
    return 0;
}
//删除数组中的文件描述符
int epoll_del_fd(int epfds,int fd)
{
    int ret = epoll_ctl(epfds, EPOLL_CTL_DEL, fd, NULL);
	if (ret < 0)
	{
		perror("fail epoll_ctl del");
		return -1;
	}
	return 0;
}

五、网页效果

相关推荐
程序猿20233 小时前
MAT(memory analyzer tool)主要功能
jvm
期待のcode6 小时前
Java虚拟机的非堆内存
java·开发语言·jvm
jmxwzy10 小时前
JVM(java虚拟机)
jvm
Maỿbe10 小时前
JVM中的类加载&&Minor GC与Full GC
jvm
人道领域11 小时前
【零基础学java】(等待唤醒机制,线程池补充)
java·开发语言·jvm
小突突突11 小时前
浅谈JVM
jvm
饺子大魔王的男人13 小时前
远程调试总碰壁?局域网成 “绊脚石”?Remote JVM Debug与cpolar的合作让效率飙升
网络·jvm
天“码”行空1 天前
java面向对象的三大特性之一多态
java·开发语言·jvm
独自破碎E1 天前
JVM的内存区域是怎么划分的?
jvm
期待のcode1 天前
认识Java虚拟机
java·开发语言·jvm