嵌入式在线商城

一、主线功能

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;
}

五、网页效果

相关推荐
Joeysoda4 小时前
Java数据结构 时间复杂度和空间复杂度
java·开发语言·jvm·数据结构·学习·算法
18你磊哥4 小时前
java重点学习-JVM组成
java·开发语言·jvm
蜜桃小阿雯6 小时前
JAVA开源项目 校园美食分享平台 计算机毕业设计
java·jvm·spring boot·spring cloud·intellij-idea·美食
longlongqin7 小时前
JIT(即时编译)技术
jvm
ZachOn1y13 小时前
Java 入门指南:JVM(Java虚拟机)—— 双亲委派模型(Parent Delegation Model)
java·jvm·后端·java-ee·团队开发·个人开发
寻求出路的程序媛14 小时前
JVM —— 类加载器的分类,双亲委派机制
java·jvm·面试
深鱼~14 小时前
【JVM】垃圾回收机制|死亡对象的判断算法|垃圾回收算法
jvm
Lill_bin14 小时前
JVM内部结构解析
jvm·后端·spring cloud·微服务·云原生·ribbon
视觉小鸟15 小时前
【JVM安装MinIO】
前端·jvm·chrome
ZachOn1y16 小时前
Java 入门指南:JVM(Java虚拟机)垃圾回收机制 —— 新一代垃圾回收器 ZGC 收集器
java·开发语言·jvm·后端·java-ee·个人开发