Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2272001
  • 博文数量: 102
  • 博客积分: 1444
  • 博客等级: 中尉
  • 技术积分: 13853
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-29 10:58
文章分类

全部博文(102)

文章存档

2014年(29)

2013年(14)

2012年(59)

分类: LINUX

2013-03-18 15:36:55

1.和浏览器交互的线程

void *client_thread(void *arg)
{
request_t request = {0};
char buf[1024] = {0};
client_t *pclient = (client_t *)arg;
//接受浏览器发过来的请求
if(recv(pclient->connect_fd,buf,sizeof(buf) -1,0) < 0)
{
perror("Fail to recv");
pthread_exit(NULL);
}

//分析请求
if(analysis_http_request(buf,&request) < 0){
pthread_exit(NULL);
}

//应答浏览器
switch(request.type)
{
case A_FILE:
send_file(pclient->connect_fd,request.parm,pclient->www_dir);
break;

case A_SNAPSHOT:
send_snapshot(pclient->connect_fd);
break;

case A_STREAM:
send_stream(pclient->connect_fd);
break;
}

close(pclient->connect_fd);
free(pclient->www_dir);
printf("free pclient->www_dir ok.\n");
free(pclient);
printf("free pclient ok.\n");
free(request.parm);
printf("free request.parm ok.\n");

return NULL;
}

2.接受客户端发送的请求

int accept_http_request(int sockfd,char *buf)
{
fd_set fds;
int ret;
int n = 0,offset = 0;
struct timeval tv = {5,0};

while(1)
{
FD_ZERO(&fds);
FD_SET(sockfd,&fds);

if((ret = select(sockfd + 1,&fds,NULL,NULL,&tv)) <= 0)
{
if(ret < 0){
perror("Fail to select");
return -1;
}

break;
}
if((n = recv(sockfd,buf + offset,BUFFER_SIZE - offset,0)) < 0)
{
perror("Fail to recv");
return -1;
}
#if 0
printf("***********************************\n");
printf("%s\n",buf);
printf("***********************************\n");
#endif 
offset += n;

if(offset >= sizeof(buf) - 1)
break;
}
return 0;
}

3.分析请求的内容

int analysis_http_request(char *buf,request_t *req)
{
int len = 0;
char *p = NULL;

/* determine what to deliver */
if ( strstr(buf, "GET /?action=snapshot") != NULL ) {
req->type = A_SNAPSHOT;
return 0;
}else if ( strstr(buf, "GET /?action=stream") != NULL ) {
req->type = A_STREAM;
return 0;
}else{

if((p = strstr(buf,"GET /")) == NULL)
{
printf("Http request error.\n");
//send error to client
return -1;
}

p += strlen("GET /");
len = MIN(MAX(strspn(p, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-1234567890"), 0), 100);
req->parm = (char *)malloc(len + 1);
memset(req->parm,0,len+1);
memcpy(req->parm,p,len);
printf("req->parm : %s.\n",req->parm);
req->type = A_FILE;
}

return 0;
}

4.发送一副静态图片

void send_snapshot(int sockfd)
{
int length;
char *frame;
char buf[BUFFER_SIZE];

pthread_mutex_lock(&global.update_lock);

pthread_cond_wait(&global.update_cond,&global.update_lock);
//获得视频数据
length = global.length;
frame  = (char *)malloc(global.length);
memcpy(frame,global.start,global.length);
pthread_mutex_unlock(&global.update_lock);

//添加http头
    memset(buf,0,sizeof(buf));
sprintf(buf, "HTTP/1.0 200 OK\r\n" \
                 "Content-type: image/jpeg\r\n" \
                 STD_HEADER \
           "\r\n");

//发送http头
if(send(sockfd,buf,strlen(buf),0) < 0)
{
free(frame);
return;
}

//发送视频数据  
if(send(sockfd,frame,length,0) < 0)
{
free(frame);
return;
}

free(frame);

return;
}

5.发送视频流

void send_stream(int sockfd)
{
int length;
char *frame;
char buf[BUFFER_SIZE];
printf("send_stream\n");

   sprintf(buf, "HTTP/1.1 200 OK\r\n" \
                  STD_HEADER \
                  "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n" \
                  "\r\n" \
                  "--" BOUNDARY "\r\n");
//send to http head 
if(send(sockfd,buf,strlen(buf),0) < 0)
{
perror("fail to send http head");
return;
}

printf("send http head ok\n");
while(!global.stop)
{
pthread_mutex_lock(&global.update_lock);
pthread_cond_wait(&global.update_cond,&global.update_lock);
//获得视频数据
length = global.length;
frame  = (char *)malloc(global.length);
memcpy(frame,global.start,global.length);
pthread_mutex_unlock(&global.update_lock);
/* print the individual mimetype and the length
 * sending the content-length fixes random stream disruption observed
 * with firefox
 */
sprintf(buf, "Content-Type: image/jpeg\r\n" \
"Content-Length: %d\r\n" \
"\r\n",length);
//sending intermdiate header
if(send(sockfd,buf,strlen(buf),0) < 0)
{
perror("Fail to send intermdiate header");
return;
}

printf("send intermdiate header.\n");
//sending camera frame 
if(send(sockfd,frame,length,0) < 0)
{
perror("Fail to send camera frame");
return;
}

sprintf(buf, "\r\n--" BOUNDARY "\r\n");
if ( send(sockfd, buf, strlen(buf),0) < 0 ) break;
free(frame);
}

return;
}

6.发送普通文件

void send_file(int sockfd,char *pathfile,char *www_dir)
{
int n,fd,i;
char buf[1024] = {0};
    char *extension, *mimetype=NULL;
    
if(pathfile == NULL || strlen(pathfile) == 0)
pathfile = "index.html";
    /* find file-extension */
    if ( (extension = strstr(pathfile, ".")) == NULL ) {
    //    send_error(fd, 400, "No file extension found");
        return;
    }

    /* determine mime-type */
    for ( i=0; i < LENGTH_OF(mimetypes); i++ ) {
        if ( strcmp(mimetypes[i].dot_extension, extension) == 0 ) {
            mimetype = (char *)mimetypes[i].mimetype;
            break;
        }
    }
    
    /* in case of unknown mimetype or extension leave */
    if ( mimetype == NULL ) {
    //    send_error(fd, 404, "MIME-TYPE not known");
        return;
    }

//打开文件 
sprintf(buf,"%s/%s",www_dir,pathfile);
if((fd = open(buf,O_RDONLY)) < 0)
{
fprintf(stderr,"Fail to open %s : %s.\n",buf,strerror(errno));
//send error to webbrowser
return;
}

// printf("pathfile : %s.\n",buf);

//添加http头
    memset(buf,0,sizeof(buf));
sprintf(buf, "HTTP/1.0 200 OK\r\n" \
                 "Content-type: %s\r\n" \
                 STD_HEADER \
                 "\r\n",mimetype);
    n = strlen(buf);
//发送http头信息和网页
do{
send(sockfd,buf,n,0);
}while(n = read(fd,buf,sizeof(buf)));

return;

最后附上整个系统的代码:video_server.zip
阅读(3269) | 评论(1) | 转发(6) |
给主人留下些什么吧!~~