文章目录
总体框架:
先分析main.c
int main(int argc, char **argv)
{
//初始化一些锁和条件变量
//pthread_mutex_init (&mutex_slinklist, NULL);
pthread_mutex_init (&mutex_uart_cmd, NULL);
//pthread_mutex_init (&mutex_main_thread, NULL);
pthread_mutex_init (&mutex_camera, NULL);
//pthread_mutex_init (&mutex_refresh, NULL);
//pthread_mutex_init (&mutex_refresh_updata, NULL);
//pthread_mutex_init (&mutex_global, NULL);
pthread_mutex_init (&mutex_linklist, NULL);
//pthread_cond_init (&cond_zigbee_rcv, NULL);
pthread_cond_init (&cond_uart_cmd, NULL);
//pthread_cond_init (&cond_main_thread, NULL);
pthread_cond_init (&cond_camera, NULL);
pthread_cond_init (&cond_refresh, NULL);
//pthread_cond_init (&cond_refresh_updata, NULL);
signal (SIGINT, ReleaseResource);//注册信号,如果按下ctrl+c那么就释放资源
//创建线程
pthread_create (&id_zigbee_rcv, 0, pthread_zigbee_rcv, NULL);
sleep (1);
pthread_create (&id_uart_cmd, 0, pthread_uart_send, NULL);
pthread_create (&id_main_thread, 0, pthread_main, NULL);
pthread_create (&id_camera, 0, pthread_camera, NULL);
pthread_create (&id_refresh, 0, pthread_refresh, NULL);
//主线程等待线程
pthread_join (id_zigbee_rcv, NULL);
printf ("g1\n");
pthread_join (id_uart_cmd, NULL);
printf ("g2\n");
pthread_join (id_main_thread, NULL);
printf ("g3\n");
pthread_join (id_camera, NULL);
printf ("g4\n");
pthread_join (id_refresh, NULL);
printf ("g5\n");
return 0;
}
main.c的作用:初始化互斥锁与条件变量,并创建5个线程。这5个线程可以分为两类:
一、接收->显示类
消息经过:
zigbee->pthread_zigbee_rcv->pthread_refresh->cgi->html
1. pthread_zigbee_rcv
void *pthread_zigbee_rcv (void *arg)
{
int i = 0, len;
char flag = 0, check;
link_datatype buf;
envlinkHead = CreateEmptyLinklist ();//创建空链表函数,在list.c中定义
#if 1
if ((dev_uart_fd = open (DEV_ZIGBEE, O_RDWR)) < 0)//打开串口
{
perror ("open ttyUSB0 fail");
// exit (-1);
// return -1;
}
serial_init (dev_uart_fd);//初始化串口配置
printf ("pthread_transfer is ok\n");
#endif
while (1)
{
memset (&buf, 0, sizeof (link_datatype));
read (dev_uart_fd, &check, 1);
/* if (check == 'c')
{
sendMsgQueue(MSG_ZIGBEE,MSG_CONNECT_SUCCESS);
}*/
if (check == 's')
{
check = 0;
read (dev_uart_fd, &check, 1);
if (check == 't')
{
check = 0;
read (dev_uart_fd, &check, 1);
if (check == ':')
{
check = 0;
read (dev_uart_fd, &check, 1);
if (check == 'e')
{
buf.msg_type = 'e';
usleep(1);
if ((len = read (dev_uart_fd, buf.text, LEN_ENV)) != LEN_ENV)
{
for (i = len; i < LEN_ENV; i++)
{
read (dev_uart_fd, buf.text+i, 1);
}
}
flag = 1;
}
}
}
}
if (1 == flag)//如果成功读取到20字节的数据
{
pthread_mutex_lock (&mutex_linklist);
//接收到的额数据加入到链表中
if ((InsertLinknode (buf)) == -1)
{
pthread_mutex_unlock (&mutex_linklist);
printf ("NONMEM\n");
}
pthread_mutex_unlock (&mutex_linklist);
flag = 0;
pthread_cond_signal (&cond_refresh);//唤醒refresh线程的条件变量
}
}
return 0;
}
主要作用:
创建链表,初始化串口配置,接收消息,并将消息放入链表中。由于链表是临界资源,要用互斥锁和条件变量。
2. pthread_refresh
void *pthread_refresh (void *arg)
{
key_t key_info;
int shmid, semid;//定义信号量与共享内存
linklist node;
link_datatype buf;
struct shm_addr *shm_buf;//自定义共享内存
if ((key_info = ftok ("/app", 'i')) < 0)
{
perror ("ftok info");
exit (-1);
}
//初始化信号量
if ((semid = semget (key_info, 1, IPC_CREAT | IPC_EXCL |0666)) < 0)
{
if (errno == EEXIST)
{
semid = semget (key_info, 1, 0666);
}
else
{
perror ("semget");
exit (-1);
}
}
else
{
init_sem (semid, 0, 1);
}
//初始化共享内存
if ((shmid = shmget (key_info, N, IPC_CREAT | IPC_EXCL | 0666)) < 0)
{
if (errno == EEXIST)
{
shmid = shmget (key_info, N, 0666);
shm_buf = (struct shm_addr *)shmat (shmid, NULL, 0);
}
else
{
perror ("shmget");
exit (-1);
}
}
else
{
if ((shm_buf = (struct shm_addr *)shmat (shmid, NULL, 0)) == (void *)-1)
{
perror ("shmat");
exit (-1);
}
}
//清0共享内存
bzero (shm_buf, sizeof (struct shm_addr));
printf ("pthread_refresh is ok\n");
while (1)
{
pthread_mutex_lock (&mutex_linklist);//与条件变量结合的互斥锁往往是和条件变量成立之后访问的临界资源相关的所以这里应该与其结合的是mutex_linklist
pthread_cond_wait (&cond_refresh, &mutex_linklist);
while (1)
{
//pthread_mutex_lock (&mutex_linklist);
if ((node = GetLinknode (envlinkHead)) == NULL)
{
pthread_mutex_unlock (&mutex_linklist);
break;
}
buf = node->data;
free (node);
pthread_mutex_unlock (&mutex_linklist);
if ('e' == buf.msg_type)
{
getEnvPackage (&buf);//整理数据,填充到节点对应结构体中,等待共享内存
}
}
//共享内存shm_buf需要由进程信号量来控制互斥访问
sem_p (semid, 0);
//pthread_mutex_lock (&mutex_global);//在同一个线程中没有使用互斥锁的必要
shm_buf->rt_status = all_info_RT;//共享内存
//pthread_mutex_unlock (&mutex_global);
sem_v (semid, 0);
//pthread_mutex_unlock (&mutex_refresh);
}
return 0;
}
作用:
初始化信号量与共享内存,将链表中的消息读取(从尾部一个一个),然后将数据进行处理好放入共享内存中,最后使用共享内存共享。
细节:
要使用信号量来互斥,因为是进程间,并且在内存共享之前的数据处理是根据节点来的,每个节点都有一块内存在all_info_RT中。
3. cgi读取
int cgiMain()
{
key_t key;
int shmid,semid;
struct shm_addr *shm_buf;//定义共享内存
if((key = ftok("/app",'i')) <0)
{
perror("ftok");
exit(1);
}
printf("key = %x\n",key);
//获取信号量
if((semid = semget(key, 1, 0666)) < 0)
{
perror("semget");
exit(1);
}
//申请共享内存
if((shmid = shmget(key, N, 0666 )) == -1)
{
perror("shmget");
exit(1);
}
if((shm_buf = (struct shm_addr*)shmat(shmid, NULL, 0)) == (void*)-1 )
{
perror("shmat");
exit(1);
}
sem_p(semid,0);
cgiHeaderContentType("text/html");//在输出html之前都要执行这个
//输出html回网页
fprintf(cgiOut, "<head><meta http-equiv=\"refresh\" content=\"1\"><style><!--body{line-height:50%}--></style></head>");
fprintf(cgiOut, "<HTML>\n");
fprintf(cgiOut, "<BODY bgcolor=\"#666666\">\n");
fprintf(cgiOut, "<h1><font color=\"#FF0000\">ENDPOINT #%d</font></H2>\n ", STO_NO);
if (shm_buf->zg_status.env_no[STO_NO].storage_status == 1)
{
fprintf(cgiOut, "<h2><font face=\"Broadway\"><font color=\"#FFFAF0\">Real-time information environment</font></font></H2>\n ");
fprintf(cgiOut, "<h4>Temperature:\t%0.2f</H4>\n ", shm_buf->zg_status.env_no[STO_NO].temperature);
// fprintf(cgiOut, "<h4>Humidity:\t%0.2f</H4>\n ", shm_buf->zg_status.env_no[STO_NO].humidity);
fprintf(cgiOut, "<h4>Light:\t%d</H4>\n ", shm_buf->zg_status.env_no[STO_NO].illumination);
fprintf(cgiOut, "<h4>Gas:\t%d</H4>\n ", shm_buf->zg_status.env_no[STO_NO].gas);
// fprintf(cgiOut, "<h4>Adc:\t%0.2f</H4>\n ", shm_buf->zg_status.env_no[STO_NO].adc);
// 红外
if(shm_buf->zg_status.env_no[STO_NO].hongwai == 1)
{
fprintf(cgiOut, "<h4>有人\t</H4>\n ");
}else{
fprintf(cgiOut, "<h4>无人\t</H4>\n ");
}
}
else
{
fprintf(cgiOut, "<h2><font face=\"Broadway\"><font color=\"#FFFAF0\">Close!</font></font></H2>\n ");
}
// fprintf(cgiOut, "<h3>:</H3>\n ");
fprintf(cgiOut, "</BODY></HTML>\n");
sem_v (semid, 0);
return 0;
}
二、发送命令类(发送给linux的摄像头/zigbee的单片机)
pthread_create (&id_zigbee_rcv, 0, pthread_zigbee_rcv, NULL);
sleep (1);
pthread_create (&id_uart_cmd, 0, pthread_uart_send, NULL);
pthread_create (&id_main_thread, 0, pthread_main, NULL);
pthread_create (&id_camera, 0, pthread_camera, NULL);
pthread_create (&id_refresh, 0, pthread_refresh, NULL);
消息经过:
html表单数据->cgi获取->cgi发送数据到消息队列->pthread_main->pthread_camera/pthread_uart_send
比如开led操作:
1. zigbee_led.c
int cgiMain()
{
key_t key;
char buf[N];
char ep_no[2];
int msgid;
struct msg msg_buf;
memset(&msg_buf,0,sizeof(msg_buf));
cgiFormString("led",buf,N);//获取网页led状态
cgiFormString("store",ep_no,2);//获取节点信息
if((key = ftok("/app", 'g')) < 0)
{
perror("ftok");
exit(1);
}
//初始化消息队列
if((msgid = msgget(key, 0666)) < 0)
{
perror("msgget");
exit(1);
}
//清空消息队列
bzero (msg_buf.text, sizeof (msg_buf.text));
msg_buf.text[0] = born_cmd(ep_no[0],DEVICE_LED,(buf[0]-48));
msg_buf.type = 1L;//这个是消息队列发送方和接收方定好的标准,一定要一样
msg_buf.msgtype = 4L;//自己定义的用于区分是发给pthread_camera/pthread_uart_send
msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0);//发送消息队列
ep_no[0] -= 48;
//回写html
cgiHeaderContentType("text/html\n\n");
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>My CGI</TITLE></HEAD>\n");
fprintf(cgiOut, "<BODY>");
fprintf(cgiOut, "<H2>send sucess</H2>");
//fprintf(cgiOut, "<a href='.html'>返回</a>");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../control%d.html\">", ep_no[0]);
fprintf(cgiOut, "</BODY>\n");
fprintf(cgiOut, "</HTML>\n");
return 0;
}
主要作用:
通过cgiFormString读取html上对应设备与节点信息,然后使用消息队列发送给pthread_main
二、pthread_main
void *pthread_main (void *arg)
{
key_t key;
ssize_t msgsize;
struct msg msgbuf;
//获得消息队列
if ((key = ftok ("/app", 'g')) < 0)
{
perror ("ftok msgqueue");
exit (-1);
}
if ((msgid = msgget (key, IPC_CREAT | IPC_EXCL | 0666)) < 0)
{
if(errno == EEXIST)
{
msgid = msgget (key,0666);
return 0;
}
else
{
perror ("msgget msgid");
exit (-1);
}
}
//创建发送链表
zigbee_cache_head = CreateEmptyCacheList ();
zigbee_cache_tail = zigbee_cache_head;
unsigned char *zigbee_temp;
printf ("pthread_main is ok\n");
while (1)
{
bzero (&msgbuf, sizeof (msgbuf));
printf ("\nwait for the msg\n");
msgsize = msgrcv (msgid, &msgbuf, sizeof (msgbuf) - sizeof (long), 1L, 0);//注意里面的1L是标志,要与上面的cgi中一样
printf (" Get %ldL msg [%ld]\n", msgbuf.msgtype,msgsize);
printf (" text[0] = %#x\n", msgbuf.text[0]);
switch (msgbuf.msgtype)
{
case MSG_CAMERA:
{//发送给camera控制线程
pthread_mutex_lock (&mutex_camera);
dev_camera_mask = msgbuf.text[0];
pthread_cond_signal (&cond_camera);
pthread_mutex_unlock (&mutex_camera);
break;
}
case MSG_ZIGBEE:
{//zigbee发送命令
//usleep (200000);
pthread_mutex_lock (&mutex_uart_cmd);
zigbee_temp = (unsigned char *)malloc (sizeof (unsigned char));
*zigbee_temp = msgbuf.text[0];
printf(" msgbuf.text = %x\n",msgbuf.text[0]);
InsertCacheNode (&zigbee_cache_tail, zigbee_temp);
//dev_uart_mask = msgbuf.text[0];
pthread_mutex_unlock (&mutex_uart_cmd);
pthread_cond_signal (&cond_uart_cmd);
break;
}
default :
break;
}
}
}
如果是MSG_CAMERA:pthread_camera
void *pthread_camera (void *arg)
{
unsigned char picture = 0;
#if 1
if ((dev_camera_fd = open (DEV_CAMERA, O_RDWR | O_NOCTTY | O_NDELAY)) < 0)//打开摄像头
{
printf ("Cann't open file %s\n",DEV_CAMERA);
// exit (-1);
}
printf ("pthread_camera is ok\n");
#endif
while (1)
{
pthread_mutex_lock (&mutex_camera);
pthread_cond_wait (&cond_camera, &mutex_camera);
picture = dev_camera_mask;//获取拍几张照片
pthread_mutex_unlock (&mutex_camera);
#if 1
for (; picture > 0; picture--)
{
//write (dev_camera_fd, "one", 3); //无效
system("echo one > /tmp/webcom"); //ok,拍几张照片
printf("picture = %d\n", picture);
sleep(4);
}
#endif
}
}
主要作用:
打开摄像头,获取到拍几张照之后,直接使用system命令就可以
MSG_ZIGBEE:pthread_uart_send
void *pthread_uart_send (void *arg)
{
unsigned char *uart_p = NULL;
uart_cache_list uart_cache_p = NULL;
printf ("pthread_uart_send is ok\n");
while (1)
{
pthread_mutex_lock (&mutex_uart_cmd);
pthread_cond_wait (&cond_uart_cmd, &mutex_uart_cmd);
while ((uart_cache_p = GetCacheNode (zigbee_cache_head, &zigbee_cache_tail)) != NULL)
{
pthread_mutex_unlock (&mutex_uart_cmd);
uart_p = (unsigned char *)uart_cache_p->data;
dev_uart_mask = *uart_p;
write (dev_uart_fd, &dev_uart_mask, 1);//通过串口写cmd
printf("\tuart:m0 cmd = %x\n", dev_uart_mask);
free (uart_p);
uart_p = NULL;
free (uart_cache_p);
uart_cache_p = NULL;
usleep (200000);
pthread_mutex_lock (&mutex_uart_cmd);
}
pthread_mutex_unlock (&mutex_uart_cmd);
}
}
主要作用:
从发送链表中读取命令,并提供串口发送出去给zigbee,这里的dev_uart_fd是在pthread_zigbee_rcv线程创建的。
细节:在线程中,任何一方打开的文件,都可以被其它线程read/write,前提文件描述符应该是全局变量
三、sqqlite
我们的项目中还用到了sqlite是在登录页面与注册页面上。
主要的操作是login.c与regist.c的两个cgi文件。
1. regist.c
int cgiMain()
{
char userbuf[10], pwbuf[10];
char sql[1024], **result, *errmsg;
int nrow, ncolumn;
sqlite3 *db;//定义数据库
if(sqlite3_open("user.db",&db) != 0)//打开数据库中的user.db,注意这个地址是相对.cgi程序的,而编译好的.cgi要放在/www/cgi-bin中,所以这样user.db也要放在这个目录下,不然就使用绝对地址
{
printf("open user.db failed!\n");
exit(-1);
}
//获取用户名密码
cgiFormString("username",userbuf,10);
cgiFormString("userpass",pwbuf,10);
sprintf(sql,"insert into user values('%s','%s');",userbuf,pwbuf);//用户名密码插入表中
//回写html
if(sqlite3_exec(db, sql, NULL, NULL, &errmsg) != 0)
{
perror("sqlite3_exec()\n");
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<HTML>\n");
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>logining</TITLE></HEAD>\n");
fprintf(cgiOut, "<BODY>");
fprintf(cgiOut, "<H1>%s<Hi>","username or password is not right,please try again");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../index.html\">");
}
else{
cgiHeaderContentType("text/html");
// fprintf(cgiOut,"<request.seCharcterEncoding(%s);>",buf);
fprintf(cgiOut, "<HTML>\n");
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>regist</TITLE></HEAD>\n");
fprintf(cgiOut, "<BODY>");
fprintf(cgiOut, "<H1>%s<Hi>","regist successfully,skipping...");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"1;url=../index.html\">");
}
return 0;
}
2. login.c
int cgiMain()
{
char userbuf[10], pwbuf[10];
char sql[1024], **result, *errmsg;
int nrow, ncolumn;
sqlite3 *db;
if(sqlite3_open("user.db",&db) != 0)
{
printf("open user.db failed!\n");
exit(-1);
}
cgiFormString("username",userbuf,10);
cgiFormString("userpass",pwbuf,10);
sprintf(sql,"select * from user where name='%s' and password='%s';",userbuf,pwbuf);
//执行组合好的select语句,并返回结果集的row与colume
if(sqlite3_get_table(db,sql,&result,&nrow,&ncolumn,&errmsg) != 0)
{
perror("sqlite3_get_table");
exit(-1);></HEAD>\n");
fprintf(cgiOut, "<BODY>")
}
//如果没找到,说明没注册
if(nrow == 0)
{
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<HTML>\n");
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>logining</TITLE;
fprintf(cgiOut, "<H1>%s<Hi>","username or password is not right,please try again");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"2;url=../index.html\">");
}
else{//如果登录成功加载main.html
cgiHeaderContentType("text/html");
// fprintf(cgiOut,"<request.seCharcterEncoding(%s);>",buf);
fprintf(cgiOut, "<HTML>\n");
fprintf(cgiOut, "<HTML><HEAD>\n");
fprintf(cgiOut, "<TITLE>logining</TITLE></HEAD>\n");
fprintf(cgiOut, "<BODY>");
fprintf(cgiOut, "<H1>%s<Hi>","login successfully,skipping...");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"0;url=../main.html\">");
}
return 0;
}
四、拍照功能(结合mjpeg-stream进程,只需让linux下执行相应的命令就能拍照,并且照片放在指定目录下)
1. capture.c
int cgiMain()
{
key_t key;
char buf[N];
int msgid;
struct msg msg_buf;
memset(&msg_buf,0,sizeof(msg_buf));
// int camera_fd;
// int len = buf[0] - 48;
cgiFormString("mode",buf,N);
if(buf[0] <= '0' || buf[0] > '9')
goto err;
if((key = ftok("/app", 'g')) < 0)
{
perror("ftok");
exit(1);
}
if((msgid = msgget(key, 0666)) < 0)
{
perror("msgget");
exit(1);
}
// msg_buf.text[0] = buf[0];
msg_buf.text[0] = buf[0] - 48;
msg_buf.type = 1L;
msg_buf.msgtype = 3L;
msgsnd(msgid, &msg_buf,sizeof(msg_buf)-sizeof(long),0);//发送消息队列
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<HTML><HEAD>");
fprintf(cgiOut, "<TITLE>操作提示</TITLE></HEAD>");
fprintf(cgiOut, "<BODY BGCOLOR=\"#EEF2FB\">");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"3; url=../video.html\">");
fprintf(cgiOut, "<H2>抓拍<font color=\"#FF0000\" size=\"+3\">成功!</font>本页面3秒后自动关闭。</H2>");
fprintf(cgiOut, "<H2>您抓拍了%d张</H2>", buf[0] - '0');
fprintf(cgiOut, "<script type=\"text/jscript\">");
fprintf(cgiOut, "setTimeout(\"self.close()\", 20000)");
fprintf(cgiOut, "</script>");
fprintf(cgiOut, "</BODY>");
fprintf(cgiOut, "</HTML>");
fflush(stdout);
return 0;
err:
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<HTML><HEAD>");
fprintf(cgiOut, "<TITLE>操作提示</TITLE></HEAD>");
fprintf(cgiOut, "<BODY BGCOLOR=\"#EEF2FB\">");
fprintf(cgiOut, "<meta http-equiv=\"refresh\" content=\"3; url=../video.html\">");
fprintf(cgiOut, "<H2>抓拍<font color=\"#FF0000\" size=\"+3\">失败!</font>本页面3秒后自动关闭。</H2>");
fprintf(cgiOut, "<H2>您抓拍了0张</H2>");
fprintf(cgiOut, "<script type=\"text/jscript\">");
fprintf(cgiOut, "setTimeout(\"self.close()\", 20000)");
fprintf(cgiOut, "</script>");
fprintf(cgiOut, "</BODY>");
fprintf(cgiOut, "</HTML>");
fflush(stdout);
return 0;
}
2. picture.c(显示历史图片)
int cgiMain()
{
DIR *dir;
struct dirent *dirp;
char photoname[PHOTO_NUM_MAX][48]; // 最多100张,0-99
struct _syncmsg1 syncmsg1 = {0, 0, 0}; //cgi中操作的数据
struct _syncmsg2 syncmsg2 = {{0}, {0}, {0}};//web页面传来数据
char path[256] = {0};
if((dir = opendir(DIRNAME)) == NULL) //打开图片存放的目录
{
perror("fail to opendir");
exit(1);
}
while((dirp = readdir(dir)) != NULL) //读文件夹里文件的名字
{
if(dirp->d_name[0] > '9' || dirp->d_name[0] < '0') //名字的第一个字母
continue;
sprintf(photoname[syncmsg1.photo_num++], "%s", dirp->d_name);
if(syncmsg1.photo_num >= PHOTO_NUM_MAX) //判断是否超过最大值
{
syncmsg1.photo_num = PHOTO_NUM_MAX - 1;
break;
}
}
syncmsg1.photo_num -= 1;
cgiFormString("number", syncmsg2.number,13); //网页传来的名字
cgiFormString("index", syncmsg2.index,13); //网页传来的指针
cgiFormString("action", syncmsg2.action,13); //网页传来的互动标志
if(syncmsg2.number == NULL || syncmsg2.index == NULL || syncmsg2.action == NULL) //第一次浏览
{
syncmsg1.photo_idx = 0; // 浏览第一张指针,最多100张,0-99
syncmsg1.key_action = 0; // 浏览第一张行为,最多100张,0-99
}
else
{
syncmsg1.photo_idx = atoi(syncmsg2.index); //把字符串转换成整型数
if(syncmsg1.photo_idx > syncmsg1.photo_num) //
syncmsg1.photo_idx = syncmsg1.photo_num;
// if(syncmsg2.action[2] == 0x8A) //prev
if(syncmsg2.action[0] == 'p')
syncmsg1.key_action = 1; //进入上一张
// else if(syncmsg2.action[2] == 0x8B) //next
else if(syncmsg2.action[0] == 'n')
syncmsg1.key_action = 2; //进入下一张
}
switch(syncmsg1.key_action)
{
case 0: // 浏览第一张行为
sprintf(path, "%s/%s", DIRNAME, photoname[syncmsg1.photo_idx]);
sprintf(syncmsg2.number, "%d", syncmsg1.photo_num);
sprintf(syncmsg2.index, "%d", syncmsg1.photo_idx);
break;
case 1: // 浏览上一张行为
if(syncmsg1.photo_idx >= syncmsg1.photo_num)
syncmsg1.photo_idx = 0;
else
syncmsg1.photo_idx = syncmsg1.photo_idx + 1;
sprintf(path, "%s/%s", DIRNAME, photoname[syncmsg1.photo_idx]);
sprintf(syncmsg2.number, "%d", syncmsg1.photo_num);
sprintf(syncmsg2.index, "%d", syncmsg1.photo_idx);
break;
case 2: // 浏览下一张行为
if(syncmsg1.photo_idx <= 0)
syncmsg1.photo_idx = syncmsg1.photo_num;
else
syncmsg1.photo_idx = syncmsg1.photo_idx - 1;
sprintf(path, "%s/%s", DIRNAME, photoname[syncmsg1.photo_idx]);
sprintf(syncmsg2.number, "%d", syncmsg1.photo_num);
sprintf(syncmsg2.index, "%d", syncmsg1.photo_idx);
break;
default:
break;
}
cgiHeaderContentType("text/html");
fprintf(cgiOut, "<HTML><HEAD>");
fprintf(cgiOut, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />");
fprintf(cgiOut, "<TITLE>历史照片信息</TITLE>");
fprintf(cgiOut, "<style type=\"text/css\"> body,td,th {font-size: 12px;margin-left: 0px;margin-top: 0px;}</style></HEAD>");
fprintf(cgiOut, "<BODY BGCOLOR=\"#F8F9FA\">");
// fprintf(cgiOut, "<H1>number:%d index:%d action:%d<Hi>",syncmsg1.photo_num,syncmsg1.photo_idx,syncmsg1.key_action);
// fprintf(cgiOut, "<H1>number:%s index:%s action:%s<Hi>",syncmsg2.number,syncmsg2.index,syncmsg2.action);
fprintf(cgiOut, "<img src=\"%s\" width=\"560\" height=\"420\" /></br>", path);
#if 1
fprintf(cgiOut, "<table width=\"560\" border=\"0\" align=\"left\" cellpadding=\"0\" cellspacing=\"0\">");
fprintf(cgiOut, "<form id=\"show_photo\" name=\"show_photo\" method=\"post\" action=\"./picture1.cgi\">");
fprintf(cgiOut, "<tr>");
fprintf(cgiOut, "<td height=\"30\" colspan=\"7\" align=\"center\"><input name=\"photoname\" style=\"background:transparent;border:1px solid #F8F9FA\" type=\"text\" id=\"photoname\" value=\"%s\" size=\"40\" maxlength=\"100\" readonly=\"readonly\"/></td>", photoname[syncmsg1.photo_idx]);
fprintf(cgiOut, "</tr>");
fprintf(cgiOut, "<tr>");
fprintf(cgiOut, "<td height=\"30\" width=\"30%%\"><input style=\"display:none\" name=\"number\" type=\"text\" id=\"number\" value=\"%s\" size=\"10\" maxlength=\"100\"/></td>", syncmsg2.number);
fprintf(cgiOut, "<td height=\"30\" width=\"15%%\" align=\"center\"><input type=\"submit\" name=\"action\" id=\"last\" value=\"prev\" /></td>"); // E4B88A E4B880 E5BCA0
fprintf(cgiOut, "<td height=\"30\" width=\"10%%\"><input style=\"display:none\" name=\"index\" type=\"text\" id=\"index\" value=\"%s\" size=\"10\" maxlength=\"100\"/></td>", syncmsg2.index);
fprintf(cgiOut, "<td height=\"30\" width=\"15%%\" align=\"center\"><input type=\"submit\" name=\"action\" id=\"next\" value=\"next\" /></td>"); // E4B88B E4B880 E5BCA0
fprintf(cgiOut, "<td height=\"30\" width=\"30%%\"></td>");
fprintf(cgiOut, "</tr>");
fprintf(cgiOut, "</form>");
fprintf(cgiOut, "</table>");
#endif
fprintf(cgiOut, "<script type=\"text/jscript\">");
fprintf(cgiOut, "setTimeout(\"self.close()\", 3000)");
fprintf(cgiOut, "</script>");
fprintf(cgiOut, "</BODY>");
fprintf(cgiOut, "</HTML>");
fflush(stdout);
closedir(dir);
return 0;
}
作用:
根据网页的是点的上一张还是下一张图片进行相应的目录读取操作。
3. 那么网页又是如何显示视频流的呢?
其实搭建好mjpeg-stream之后只需要在网页加上它的服务器地址就能访问了。
video.html:
....
<tr>
<td><table width="100%" height="31" border="0" cellpadding="0" cellspacing="0" class="nowtable">
<tr>
<td align="left" class="left_bt2"> 实时监控信息</td>
</tr>
</table></td>
</tr>
<tr>
<td height="440" align="center">
<!-- <img src="http://192.168.1.118:8080/?action=stream"/></td> -->
<script type="text/javascript" language="javascript"> //这里加了一旦js代码
//var path1 = location.href;
var path1 = location.protocol + "\/\/" + location.hostname;//获取服务器地址
var path2;
function getPath(path) {
if(path.charAt(19) == '/') {
path2 = path.slice(0,19);
} else if(path.charAt(20) == '/') {
path2 = path.slice(0,20);
} else if(path.charAt(18) == '/') {
path2 = path.slice(0,18);
} else {
path2 = "http://192.168.0.111";
}
}
getPath(path1);
document.write('<img src="'+path1+':8080/?action=stream"/>');
/*
这段代码使用 document.write() 方法在 HTML 页面中插入一个图像,<img> 元素的 src 属性设置为 path1 变量的值并 加上 :8080/?action=stream 的字符串。 可能是通过网络摄像头或流媒体服务器提供的视频流。 path1 是包含图像文件路径 的变量或字符串。
*/
</script>
</td>
</tr>
....