weixin_慕哥3021856 的學(xué)生作業(yè):
global.h
#ifndef _GLOBAL_H
#define _GLOBAL_H
#include
#include
#define MIN(a, b) ((a) < (b))? (a) : (b)
#define MAX(a, b) ((a) > (b))? (a) : (b)
#endif
server.h
#ifndef _SERVER_H
#define _SERVER_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define STD_HEADER "Connection: close\r\n" \
"Server: MJPG-Streamer/0.2\r\n" \
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0\r\n" \
"Pragma: no-cache\r\n" \
"Expires: Mon, 3 Jan 2013 12:34:56 GMT\r\n"
#define BOUNDARY "cyg-boundary"
#define WEB_DIR "www"
#define BACKLOG 10
typedef enum
{
A_SNAPSHOT,
A_STREAM,
A_FILE
} answer_t;
typedef struct
{
answer_t type;
char *parm;
} request_t;
extern int init_tcp(const char *ip, unsigned short port, int backlog);
extern int tcp_server_socket(const char *ip, const int port);
extern int accept_client(int sockfd, struct sockaddr_in *caddr);
extern void *client_thread(void *arg);
extern int analyse_http_request(const char *buf, request_t *req);
extern void send_file(int sockfd, char *filename);
extern void send_snapshot(int sockfd);
extern void send_stream(int sockfd);
#endif
server.c
#include "global.h"
#include "server.h"
static const struct
{
const char *dot_extension;
const char *mimetype;
} mimetypes[] = {
{ ".html", "text/html" },
{ ".htm", "text/html" },
{ ".css", "text/css" },
{ ".js", "text/javascript" },
{ ".txt", "text/plain" },
{ ".jpg", "image/jpeg" },
{ ".jpeg", "image/jpeg" },
{ ".png", "image/png"},
{ ".gif", "image/gif" },
{ ".ico", "image/x-icon" },
{ ".swf", "application/x-shockwave-flash" },
{ ".cab", "application/x-shockwave-flash" },
{ ".jar", "application/java-archive" },
};
int init_tcp(const char *ip, unsigned short port, int backlog)
{
int fd = 0, on = 1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
{
perror("Failed to socket for init_tcp");
return -1;
}
if (0 > setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
{
perror("Failed to setsockopt");
return -1;
}
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(port),
.sin_addr.s_addr = inet_addr(ip),
.sin_zero = {0}
};
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("Failed to bind");
return -1;
}
listen(fd, backlog);
printf("Server listen fd: %d\n", fd);
printf("Server ip: %s port: %d\n", inet_ntoa(addr.sin_addr), port);
return fd;
}
int tcp_server_socket(const char *ip, const int port)
{
int sfd, ret;
sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1)
{
perror("[ERROR] Failed to socket");
return -1;
}
struct sockaddr_in saddr;
bzero(&saddr, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(ip);
ret = bind(sfd, (const struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
if (ret == -1)
{
perror("[ERROR] bind");
return -1;
}
listen(sfd, BACKLOG);
return sfd;
}
int accept_client(int sockfd, struct sockaddr_in *caddr)
{
int cfd;
socklen_t len = sizeof(struct sockaddr_in);
cfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
if (cfd == -1)
{
perror("[ERROR] accept");
return -1;
}
return cfd;
}
void *client_thread(void *arg)
{
int rws = (int)(intptr_t)arg;
char buf[1024] = {0};
if (recv(rws, buf, sizeof(buf), 0) < 0)
{
perror("[ERROR] Failed to recv()");
close(rws);
return NULL;
}
request_t req = {
.type = 0,
.parm = NULL // 開辟空間存放http數(shù)據(jù)
};
if (analyse_http_request(buf, &req) < 0)
{
perror("Failed to analyse_http_request");
close(rws);
if (req.parm)
{
free(req.parm);
req.parm = NULL;
}
pthread_exit(NULL);
}
switch (req.type)
{
case A_FILE:
send_file(rws, req.parm);
break;
case A_SNAPSHOT:
send_snapshot(rws);
break;
case A_STREAM:
send_stream(rws);
break;
}
close(rws);
pthread_exit(NULL);
}
int analyse_http_request(const char *buf, request_t *req)
{
char *url = strstr(buf, "GET /");
if (NULL == url)
{
perror("Http request error.");
return -1;
}
printf("url: %s\n", url);
url += strlen("GET /");
char arr[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-1234567890";
int len = MIN(MAX(strspn(url, arr), 0), 100);
printf("len = %d\n", len);
req->parm = (char *)malloc(len + 1);
memset(req->parm, 0, len + 1);
memcpy(req->parm, url, len);
printf("req->parm: %s\n", req->parm);
req->type = A_FILE;
return 0;
}
void send_file(int sockfd, char *pathfile)
{
int n, fd;
char buf[1024] = {0};
char *extension = NULL, *mimetype = NULL;
if (NULL == pathfile || strlen(pathfile) == 0)
{
pathfile = "index.html";
}
// 定位到擴(kuò)展名
if (NULL == (extension = strstr(pathfile, ".")))
{
return;
}
for (int i = 0; i < (sizeof(mimetypes) / sizeof(mimetypes[0])); i++)
{
if (0 == strcmp(mimetypes[i].dot_extension, extension))
{
extension = (char *)mimetypes[i].dot_extension;
mimetype = (char *)mimetypes[i].mimetype;
break;
}
}
if (NULL == extension)
{
return;
}
// 添加默認(rèn)的MIME類型
if (NULL == mimetype)
return;
// 格式化字符串被寫入緩沖區(qū)
sprintf(buf, "%s/%s", WEB_DIR, pathfile);
printf("filepath: %s\n", buf);
if ((fd = open(buf, O_RDONLY)) < 0)
{
fprintf(stderr, "Failed to open %s: %s\n", buf, strerror(errno));
// 發(fā)送404響應(yīng)
const char *response = "HTTP/1.0 404 Not Found\r\n\r\n";
send(sockfd, response, strlen(response), 0);
return;
}
// 添加HTTP協(xié)議頭
memset(buf, 0, sizeof(buf));
sprintf(buf, "HTTP/1.0 200 OK\r\n"
"Content-type: %s\r\n" STD_HEADER "\r\n",
mimetype);
// send(sockfd, buf, strlen(buf), 0);
// 發(fā)送http頭信息和網(wǎng)頁文件數(shù)據(jù).
// 發(fā)送文件內(nèi)容
do {
if (send(sockfd, buf, strlen(buf), 0) < 0)
{
perror("[ERROR] send file content");
break;
}
} while((n = read(fd, buf, sizeof(buf)) > 0));
close(fd);
return;
}
void send_snapshot(int sockfd)
{
int length;
char *frame;
char buf[BUFFER_SIZE];
printf("send_snapshot(%d)\n", sockfd);
pthread_mutex_lock(&global.update_lock);
pthread_cond_wait(&global.update_cond, &global.update_lock);
// 獲得視頻數(shù)據(jù)
length = global.length;
frame = (char *)malloc(length);
memcpy(frame, global.start, 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");
//發(fā)送http頭
if (send(sockfd, buf, strlen(buf), 0) < 0)
{
perror("Failed to send Http header by send_snapshot()");
free(frame);
return;
}
if (send(sockfd, frame, length, 0) < 0)
{
perror("Failed to send frame by send_snapshot()");
free(frame);
return;
}
}
void send_stream(int sockfd)
{
int length;
char buf[BUFFER_SIZE];
printf("send_stream(%d)\n", sockfd);
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");
if (send(sockfd, buf, strlen(buf), 0) < 0)
{
perror("send_stream() fail to send http header");
return;
}
char *frame = NULL;
while (global.capture)
{
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);
sprintf(buf, "Content-Type: image/jpeg\r\n" \
"Content-Length: %d\r\n" \
"\r\n", length);
if (send(sockfd, buf, strlen(buf), 0) < 0)
{
perror("send_stream() Failed to send Http Header");
break;
}
if (send(sockfd, frame, length, 0) < 0)
{
perror("send_stream() Failed to send camera frame");
break;
}
}
free(frame);
return;
}
main.c
//#include "camera.h"
#include "global.h"
#include "server.h"
global_t global;
void init_global(global_t *pglobal)
{
pglobal->capture = true;
pglobal->length = 0;
if((global.start = malloc(PICTURE_SIZE)) == NULL) {
perror("Fail to malloc");
exit(EXIT_FAILURE);
}
if(pthread_mutex_init(&(pglobal->update_lock), NULL) < 0) {
perror("Fail to pthread_mutex_init");
exit(EXIT_FAILURE);
}
if(pthread_cond_init(&(pglobal->update_cond), NULL) < 0) {
perror("Fail to pthread_cond_init");
exit(EXIT_FAILURE);
}
return;
}
int main(void)
{
//init_global(&global);
#if 0
int cam_fd = init_camera("/dev/video0");
if(-1 == cam_fd){
perror("init_camera() failure!");
return -1;
}
if(-1 == init_mmap(cam_fd)){
perror("init_mmap() failure!");
return -1;
}
cam_fd = start_camera(cam_fd);
if (-1 == cam_fd)
{
perror("start_camera() failure!");
return -1;
}
#endif
struct sockaddr_in addr;
pthread_t tid;
memset(&addr, 0, sizeof(struct sockaddr_in));
int s_fd = tcp_server_socket("127.0.0.1", 8080);
while (1)
{
int rws = accept_client(s_fd, &addr);
if(0 > rws){
perror("accetp() failure");
continue;
}
printf("client fd: %d\n", rws);
int ret = pthread_create(&tid, NULL, client_thread, (void *)(intptr_t)rws);
if(0 != ret){
perror("pthread_create() failure");
continue;
}
pthread_detach(tid);
printf("Loop again\n");
}
return 0;
}
【圖片】