为了账号安全,请及时绑定邮箱和手机立即绑定

作业社区

探索学习新天地,共享知识资源!

0 提交作业
0 布置作业
0 满分作业
得分 100
学习任务

慕尼黑0001808 的学生作业:

【图片】 // global.h #ifndef _GLOBAL_H_ #define _GLOBAL_H_ #include #include typedef struct { bool capture; //0表示不采集视频数据,1表示采集视频数据. void *start; //存放视频数据的起始地址. int length; //视频数据的长度. pthread_mutex_t update_lock; //线程锁. pthread_cond_t update_cond; //线程条件变量. } global_t; extern global_t global; extern void init_global(void); extern void cleanup_global(void); #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define LENGTH_OF(x) (sizeof(x)/sizeof(x[0])) #define PICTURE_SIZE (1024 * 1024 * 1024) //预分配图片的大小:1GB. #define BUFFER_SIZE 1024 #endif //_GLOBAL_H_ //global.c #include "global.h" #include #include #include global_t global; void init_global() { global.capture = true; global.length = 0; // 初始化互斥锁 if (pthread_mutex_init(&global.update_lock, NULL) != 0) { perror("pthread_mutex_init"); exit(1); } // 初始化条件变量 if (pthread_cond_init(&global.update_cond, NULL) != 0) { perror("pthread_cond_init"); exit(1); } // 分配内存 global.start = malloc(PICTURE_SIZE); if (global.start == NULL) { perror("malloc"); exit(1); } } void cleanup_global(void) { // 停止采集 global.capture = false; // 唤醒所有等待的线程 pthread_cond_broadcast(&global.update_cond); // 释放内存 if (global.start != NULL) { free(global.start); global.start = NULL; } // 销毁条件变量和互斥锁 pthread_cond_destroy(&global.update_cond); pthread_mutex_destroy(&global.update_lock); printf("Global resources cleaned up\n"); } // camera.h #include #include #include #include #include #include #include #include #include /* 希望摄像头输出的分辨率 */ #define IMG_WIDTH 640 #define IMG_HEIGHT 480 /* 防止 RGB 超过 0~255 的限幅宏 */ #define CLIP(x) ((x)255?255:(x))) /* 申请 4 块内核 DMA 视频缓冲 */ #define BUFFER_COUNT 4 /* 摄像头真实输出宽高 */ static int width, height; /* 摄像头设备文件描述符 */ static int fd_cam; /* mmap 映射到用户空间的内核帧缓冲 */ static struct { void *start; // 内存首地址 size_t length; // 内存长度 } buffers[BUFFER_COUNT]; extern int init_camera(const char *dev); extern void cleanup_camera(void); extern int yuyv_to_jpeg_memory(unsigned char *yuyv, int w, int h, unsigned char **jpeg_data, unsigned long *jpeg_size); extern int read_frame(); extern void *start_capturing(void *arg); // camera.c #include "camera.h" #include #include #include "global.h" #include #include #include #include static int n_buffer = 0; /* 打开并初始化摄像头(YUYV 原始流) */ int init_camera(const char *dev) { // 打开摄像头设备节点 /dev/video0 fd_cam = open(dev, O_RDWR); if (fd_cam < 0) { perror("open"); return -1; } /* ---------- 告诉驱动:我要什么格式 ---------- */ struct v4l2_format fmt = {0}; // 清零结构体 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 表示这是采集设备 fmt.fmt.pix.width = IMG_WIDTH; // 希望的宽度 fmt.fmt.pix.height = IMG_HEIGHT; // 希望的高度 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; // YUYV 原始视频流 fmt.fmt.pix.field = V4L2_FIELD_NONE; // 不使用隔行扫描 // ioctl 把这个格式请求发给内核摄像头驱动 ioctl(fd_cam, VIDIOC_S_FMT, &fmt); // 驱动可能会调整分辨率,这里读取真实的值 width = fmt.fmt.pix.width; height = fmt.fmt.pix.height; struct v4l2_requestbuffers req = {0}; req.count = BUFFER_COUNT; // 要 4 块帧缓冲 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 用于视频采集 req.memory = V4L2_MEMORY_MMAP; // 采用 mmap 共享内存方式 // 请求驱动在内核里分配 4 块 DMA 内存 if (ioctl(fd_cam, VIDIOC_REQBUFS, &req) < 0) { perror("VIDIOC_REQBUFS"); close(fd_cam); return -1; } // 检查实际分配的缓冲区数量 if (req.count < 1) { fprintf(stderr, "Not enough buffers allocated: %d\n", req.count); close(fd_cam); return -1; } for (int i = 0; i < BUFFER_COUNT; i++) { struct v4l2_buffer buf = {0}; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; // 第 i 块缓冲 // 查询该缓冲区在内核中的偏移和大小 if (ioctl(fd_cam, VIDIOC_QUERYBUF, &buf) < 0) { perror("VIDIOC_QUERYBUF"); close(fd_cam); return -1; } // mmap 把这块 DMA 内存映射到进程地址空间 buffers[i].length = buf.length; buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_cam, buf.m.offset); if (buffers[i].start == MAP_FAILED) { perror("mmap"); close(fd_cam); return -1; } // 把这块缓冲区加入驱动的采集队列 if (ioctl(fd_cam, VIDIOC_QBUF, &buf) < 0) { perror("VIDIOC_QBUF"); close(fd_cam); return -1; } } enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 通知驱动开始真正采集视频数据 if (ioctl(fd_cam, VIDIOC_STREAMON, &type) < 0) { perror("VIDIOC_STREAMON"); close(fd_cam); return -1; } printf("Camera ready: %dx%d YUYV\n", width, height); n_buffer = req.count; return fd_cam; } /* 清理摄像头资源 */ void cleanup_camera(void) { if (fd_cam < 0) { return; } // 停止视频流 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd_cam, VIDIOC_STREAMOFF, &type); // 取消 mmap 映射 for (int i = 0; i < n_buffer && i < BUFFER_COUNT; i++) { if (buffers[i].start != NULL && buffers[i].start != MAP_FAILED) { munmap(buffers[i].start, buffers[i].length); buffers[i].start = NULL; } } // 关闭摄像头设备 close(fd_cam); fd_cam = -1; printf("Camera resources cleaned up\n"); } /* YUYV → JPEG 转换并存储到内存 */ int yuyv_to_jpeg_memory(unsigned char *yuyv, int w, int h, unsigned char **jpeg_data, unsigned long *jpeg_size) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row[1]; unsigned char *rgb = NULL; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); // 使用内存目标 jpeg_mem_dest(&cinfo, jpeg_data, jpeg_size); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 80, TRUE); // 质量设为 80,平衡文件大小和画质 jpeg_start_compress(&cinfo, TRUE); rgb = malloc(w * 3); if (rgb == NULL) { jpeg_destroy_compress(&cinfo); return -1; } int stride = w * 2; // YUYV 每行字节数 while (cinfo.next_scanline < h) { unsigned char *p = yuyv + cinfo.next_scanline * stride; int j = 0; // 每 4 字节表示 2 个像素 for (int i = 0; i < stride; i += 4) { int y0 = p[i]; int u = p[i+1]; int y1 = p[i+2]; int v = p[i+3]; // YUV → RGB 颜色空间转换 int c = y0 - 16, d = u - 128, e = v - 128; rgb[j++] = CLIP((298*c + 409*e + 128)>>8); rgb[j++] = CLIP((298*c -100*d -208*e +128)>>8); rgb[j++] = CLIP((298*c +516*d +128)>>8); c = y1 - 16; rgb[j++] = CLIP((298*c + 409*e + 128)>>8); rgb[j++] = CLIP((298*c -100*d -208*e +128)>>8); rgb[j++] = CLIP((298*c +516*d +128)>>8); } row[0] = rgb; jpeg_write_scanlines(&cinfo, row, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); free(rgb); return 0; } /* 取一帧并转换为 JPEG 存储到全局缓冲区 */ int read_frame() { int ret; struct v4l2_buffer buf = {0}; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; // 注意:VIDIOC_DQBUF 不需要设置 index,驱动会填充 ret = ioctl(fd_cam, VIDIOC_DQBUF, &buf); // 从驱动队列取出一帧 if (ret < 0) { if (errno != EAGAIN) { // EAGAIN 表示暂时没有数据,不是错误 perror("VIDIOC_DQBUF"); } return -1; } // 检查缓冲区索引是否有效 if (buf.index >= n_buffer || buf.index < 0) { fprintf(stderr, "Invalid buffer index: %d (max: %d)\n", buf.index, n_buffer); // 即使索引无效,也要归还缓冲区 ioctl(fd_cam, VIDIOC_QBUF, &buf); return -1; } // 将 YUYV 转换为 JPEG unsigned char *jpeg_data = NULL; unsigned long jpeg_size = 0; if (yuyv_to_jpeg_memory((unsigned char *)buffers[buf.index].start, width, height, &jpeg_data, &jpeg_size) < 0) { fprintf(stderr, "Failed to convert YUYV to JPEG\n"); ioctl(fd_cam, VIDIOC_QBUF, &buf); return -1; } pthread_mutex_lock(&global.update_lock); // 存储 JPEG 数据到全局缓冲区 if (jpeg_size > PICTURE_SIZE) { global.start = realloc(global.start, jpeg_size); if (global.start == NULL) { perror("realloc"); pthread_mutex_unlock(&global.update_lock); free(jpeg_data); ioctl(fd_cam, VIDIOC_QBUF, &buf); return -1; } } global.length = jpeg_size; memcpy(global.start, jpeg_data, jpeg_size); pthread_mutex_unlock(&global.update_lock); // 释放临时 JPEG 数据 free(jpeg_data); //唤醒等待的线程 pthread_cond_broadcast(&global.update_cond); // 还回队列继续采集 ret = ioctl(fd_cam, VIDIOC_QBUF, &buf); if (ret < 0) { perror("VIDIOC_QBUF"); return -1; } return 1; } void *start_capturing(void *arg) { int camera_fd = (int)(intptr_t)arg; fd_set fds; struct timeval tv = { .tv_sec = 5, .tv_usec = 0, }; while(global.capture) { FD_ZERO(&fds); FD_SET(camera_fd, &fds); int r = select(camera_fd+1, &fds, NULL, NULL, &tv); if(-1 == r) { if(EINTR == errno) continue; perror("Fail to select"); break; } if(0 == r) { //fprintf(stderr, "select Timeout\n"); continue; } if(-1 == read_frame()) continue; } pthread_exit(NULL); } // server.h #ifndef SERVER_H #define SERVER_H #include #include #include #include // 用于 intptr_t 类型 #include #include #include #include #include #include #include #include #include "global.h" #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" typedef enum { A_SNAPSHOT, A_STREAM, A_FILE } answer_t; //HTTP 请求 typedef struct { answer_t type; char *parm; } request_t; // TCP 服务器初始化函数 // 参数: port - 要监听的端口号 // 返回: 成功返回 socket 文件描述符,失败返回 -1 extern int init_tcp(const unsigned short port); extern void *handle_thread(void *arg); extern int analyse_http_request(const char *buf, request_t *req); extern void send_file(int sockfd, char *pathfile); extern void send_snapshot(int sockfd); extern void send_stream(int sockfd); #endif // SERVER_H //server.c #include "server.h" #include "global.h" #include #include 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 unsigned short port) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); return -1; } // 设置 SO_REUSEADDR 选项,允许重用地址 int opt = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); close(sockfd); return -1; } int ret = 0; struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { close(sockfd); perror("bind"); return -1; } ret = listen(sockfd, 10); if (ret < 0) { perror("listen"); close(sockfd); return -1; } return sockfd; } void *handle_thread(void *arg) { // 将指针转换回 int 值(使用 intptr_t 确保类型安全) int sockfd = (int)(intptr_t)arg; int ret = 0; char buffer[1024]; request_t request = { .type = A_SNAPSHOT, .parm = NULL, }; ret = recv(sockfd, buffer, sizeof(buffer), 0); if (ret < 0) { perror("recv"); goto end; } //printf("recv: %s\n", buffer); analyse_http_request(buffer,&request); switch (request.type){ case A_FILE: send_file(sockfd, request.parm); break; case A_SNAPSHOT: send_snapshot(sockfd); break; case A_STREAM: send_stream(sockfd); break; } // TODO: 在这里处理客户端连接 // 例如:读取数据、处理请求、发送响应等 end: // 关闭连接 close(sockfd); if(NULL != request.parm) { free(request.parm); request.parm = NULL; } return NULL; } int analyse_http_request(const char *buf, request_t *req) { char *url = NULL; char *url_end = NULL; if (NULL != strstr(buf, "GET /?action=snapshot")) { req->type = A_SNAPSHOT; return 0; } else if (NULL != strstr(buf, "GET /?action=stream")) { req->type = A_STREAM; return 0; }else{ url = strstr(buf,"GET /"); if (url == NULL) { return -1; } url += 5; // 跳过 "GET /" // 查找 URL 结束位置(空格、?、换行符等) url_end = url; while(*url_end && *url_end != ' ' && *url_end != '?' && *url_end != '\r' && *url_end != '\n'){ url_end++; } int len = url_end - url; if(len == 0){ // 根路径,使用默认文件 len = strlen("index.html"); req->parm = (char *)malloc(len + 1); if (req->parm == NULL) { return -1; } strcpy(req->parm, "index.html"); } else { len = MIN(len, 100); req->parm = (char *)malloc(len + 1); if (req->parm == NULL) { return -1; } memset(req->parm, 0, len + 1); memcpy(req->parm, url, len); } req->type = A_FILE; } return 0; } void send_snapshot(int sockfd) { int length; char *frame = NULL; 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); // 检查是否应该停止 if (!global.capture) { pthread_mutex_unlock(&global.update_lock); return; } //获得视频数据 length = global.length; frame = (char *)malloc(global.length); if (frame == NULL) { perror("malloc"); pthread_mutex_unlock(&global.update_lock); return; } 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(0 > send(sockfd, buf, strlen(buf), 0)) { if (errno == EPIPE || errno == ECONNRESET) { printf("Client disconnected (fd=%d)\n", sockfd); } else { printf("send_snapshot() send http head failure\n"); } free(frame); return; } //发送视频数据 if(0 > send(sockfd, frame, length, 0)){ if (errno == EPIPE || errno == ECONNRESET) { printf("Client disconnected (fd=%d)\n", sockfd); } else { printf("send_snapshot() send frame failure\n"); } } 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 head"); return; } char *frame = NULL; while (global.capture) { pthread_mutex_lock(&global.update_lock); pthread_cond_wait(&global.update_cond, &global.update_lock); // 检查是否应该停止(capture 被设置为 false) if (!global.capture) { pthread_mutex_unlock(&global.update_lock); break; } length = global.length; frame = (char *)malloc(global.length); if (frame == NULL) { perror("malloc"); pthread_mutex_unlock(&global.update_lock); break; } 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); if(0 > send(sockfd, buf, strlen(buf), 0)) { // 检测客户端断开连接 if (errno == EPIPE || errno == ECONNRESET) { printf("Client disconnected (fd=%d)\n", sockfd); } else { perror("send_stream() Fail to send http header"); } free(frame); break; } if(0 > send(sockfd, frame, length, 0)) { // 检测客户端断开连接 if (errno == EPIPE || errno == ECONNRESET) { printf("Client disconnected (fd=%d)\n", sockfd); } else { perror("send_stream() Fail to send camera frame"); } free(frame); break; } sprintf(buf, "\r\n--" BOUNDARY "\r\n"); if (0 > send(sockfd, buf, strlen(buf), 0)) { // 检测客户端断开连接 if (errno == EPIPE || errno == ECONNRESET) { printf("Client disconnected (fd=%d)\n", sockfd); } free(frame); break; } free(frame); frame = NULL; usleep(100); } if (frame != NULL) { free(frame); } printf("send_stream(%d) ended\n", sockfd); return; } void send_file(int sockfd, char *pathfile) { char *extension; const char *mimetype = NULL; char buffer[1024]; char filepath[1024]; if(NULL == pathfile || strlen(pathfile) == 0){ pathfile = "index.html"; } extension = strrchr(pathfile,'.'); if(NULL == extension) return; for(int i = 0; i < sizeof(mimetypes)/sizeof(mimetypes[0]); i++){ if(strcmp(extension,mimetypes[i].dot_extension) == 0){ mimetype = mimetypes[i].mimetype; break; } } if(NULL == mimetype){ return; } sprintf(filepath,"%s/%s",WEB_DIR,pathfile); printf("send_file() pathfile: %s\n",filepath); int fp = open(filepath,O_RDONLY); if(0 > fp){ perror("open() Fail to open file"); // 发送 404 错误响应 sprintf(buffer,"HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n%s\r\n404 Not Found\r\n",STD_HEADER); send(sockfd, buffer, strlen(buffer), 0); return; } // 构建并发送 HTTP 响应头 sprintf(buffer,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n%s\r\n",mimetype,STD_HEADER); int header_len = strlen(buffer); if(send(sockfd, buffer, header_len, 0) < 0){ perror("send_file() Fail to send header"); close(fp); return; } // 读取并发送文件内容 int n; while((n = read(fp, buffer, sizeof(buffer))) > 0){ if(send(sockfd, buffer, n, 0) < 0){ perror("send_file() Fail to send file content"); break; } } close(fp); } //main.c #include #include #include #include #include "global.h" #include "server.h" #include "camera.h" // 全局变量用于信号处理 static int server_sockfd = -1; static pthread_t camera_tid; static volatile sig_atomic_t running = 1; /* 信号处理函数:优雅关闭服务器 */ void signal_handler(int sig) { if (sig == SIGINT || sig == SIGTERM) { printf("\nReceived signal %d, shutting down gracefully...\n", sig); running = 0; // 停止采集 global.capture = false; pthread_cond_broadcast(&global.update_cond); // 关闭服务器 socket,使 accept 返回 if (server_sockfd >= 0) { close(server_sockfd); server_sockfd = -1; } } } /* 清理所有资源 */ void cleanup_resources(void) { printf("Cleaning up resources...\n"); // 停止采集并清理全局资源 cleanup_global(); // 等待摄像头线程结束 pthread_join(camera_tid, NULL); // 清理摄像头资源 cleanup_camera(); printf("All resources cleaned up\n"); } int main(int argc, char *argv[]) { // 注册信号处理函数 signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); // 先初始化全局变量,再启动摄像头线程 init_global(); int camera_fd = init_camera("/dev/video0"); if (camera_fd < 0) { printf("打开摄像头失败\n"); cleanup_global(); return -1; } if (pthread_create(&camera_tid, NULL, start_capturing, (void *)(intptr_t)camera_fd) != 0) { perror("pthread_create"); cleanup_camera(); cleanup_global(); return -1; } // 注意:不 detach,以便后续 join server_sockfd = init_tcp(8080); if (server_sockfd < 0) { perror("init_tcp"); cleanup_resources(); return -1; } pthread_t c_tid; struct sockaddr_in c_addr; socklen_t c_addr_len = sizeof(c_addr); printf("Server started on port 8080\n"); printf("Press Ctrl+C to stop the server\n"); while (running) { int new_sockfd = accept(server_sockfd, (struct sockaddr *)&c_addr, &c_addr_len); if (new_sockfd < 0) { if (!running) { // 服务器正在关闭 break; } perror("accept"); continue; } printf("New connection accepted\n"); // 将 int 值直接转换为指针传递,避免 malloc/free // 使用 intptr_t 确保类型转换安全 if (pthread_create(&c_tid, NULL, handle_thread, (void *)(intptr_t)new_sockfd) != 0) { perror("pthread_create"); close(new_sockfd); continue; } // 分离线程,让线程结束后自动清理资源 pthread_detach(c_tid); } // 清理资源 cleanup_resources(); return 0; }

得分 100
学习任务

躲在星空里_fVZ025 的学生作业:

#include #include typedef struct { char name[20]; int id; int score; } s_t; // 输入学生信息函数 void input_student(s_t students[], int n) { printf(“请输入%d个学生的信息:\n”, n); for (int i = 0; i < n; i++) { printf(“学生%d:\n”, i + 1); printf(“姓名: “); scanf(”%s”, students[i].name); printf(“学号: “); scanf(”%d”, &students[i].id); printf(“成绩: “); scanf(”%d”, &students[i].score); printf("\n"); } } // 输出学生信息函数 void output_student(s_t students[], int n) { printf(“学生信息如下:\n”); printf("-------------------------------------------------\n"); printf(“序号\t姓名\t\t学号\t成绩\n”); printf("-------------------------------------------------\n"); for (int i = 0; i < n; i++) { printf("%d\t%-10s\t%d\t%d\n", i + 1, students[i].name, students[i].id, students[i].score); } printf("-------------------------------------------------\n"); } // 返回分数最高的学生信息 s_t maxscore_student(s_t students[], int n) { int max_index = 0; // 假设第一个学生分数最高 for (int i = 1; i < n; i++) { if (students[i].score > students[max_index].score) { max_index = i; } } return students[max_index]; } // 主函数 int main() { s_t s[3]; // 输入学生信息 input_student(s, 3); // 输出所有学生信息 output_student(s, 3); // 获取并输出分数最高的学生信息 s_t max_student = maxscore_student(s, 3); printf("\n分数最高的学生信息:\n"); printf("姓名: %s\n", max_student.name); printf("学号: %d\n", max_student.id); printf("成绩: %d\n", max_student.score); return 0; }

得分 100
学习任务

慕尼黑0001808 的学生作业:

// global.h #ifndef _GLOBAL_H_ #define _GLOBAL_H_ #include #include typedef struct { bool capture; //0表示不采集视频数据,1表示采集视频数据. void *start; //存放视频数据的起始地址. int length; //视频数据的长度. pthread_mutex_t update_lock; //线程锁. pthread_cond_t update_cond; //线程条件变量. } global_t; extern global_t global; #define MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MAX(a, b) (((a) > (b)) ? (a) : (b)) #define LENGTH_OF(x) (sizeof(x)/sizeof(x[0])) #define PICTURE_SIZE (1024 * 1024 * 1024) //预分配图片的大小:1GB. #define BUFFER_SIZE 1024 #endif //_GLOBAL_H_ // server.h #ifndef SERVER_H #define SERVER_H #include #include #include #include // 用于 intptr_t 类型 #include #include #include #include #include #include #include #include #include "global.h" #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" typedef enum { A_SNAPSHOT, A_STREAM, A_FILE } answer_t; //HTTP 请求 typedef struct { answer_t type; char *parm; } request_t; // TCP 服务器初始化函数 // 参数: port - 要监听的端口号 // 返回: 成功返回 socket 文件描述符,失败返回 -1 extern int init_tcp(const unsigned short port); extern void *handle_thread(void *arg); extern int analyse_http_request(const char *buf, request_t *req); extern void send_file(int sockfd, char *pathfile); #endif // SERVER_H //server.c #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 unsigned short port) { int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); return -1; } // 设置 SO_REUSEADDR 选项,允许重用地址 int opt = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); close(sockfd); return -1; } int ret = 0; struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; ret = bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); if (ret < 0) { close(sockfd); perror("bind"); return -1; } ret = listen(sockfd, 10); if (ret < 0) { perror("listen"); close(sockfd); return -1; } return sockfd; } void *handle_thread(void *arg) { // 将指针转换回 int 值(使用 intptr_t 确保类型安全) int sockfd = (int)(intptr_t)arg; int ret = 0; char buffer[1024]; request_t request = { .type = A_SNAPSHOT, .parm = NULL, }; ret = recv(sockfd, buffer, sizeof(buffer), 0); if (ret < 0) { perror("recv"); goto end; } analyse_http_request(buffer,&request); switch(request.type) { case A_SNAPSHOT: break; case A_STREAM: break; case A_FILE: send_file(sockfd,request.parm); break; } // TODO: 在这里处理客户端连接 // 例如:读取数据、处理请求、发送响应等 end: // 关闭连接 close(sockfd); if(NULL != request.parm) { free(request.parm); request.parm = NULL; } return NULL; } int analyse_http_request(const char *buf, request_t *req) { char *url = NULL; char *url_end = NULL; url = strstr(buf,"GET /"); if (url == NULL) { return -1; } url += 5; // 跳过 "GET /" // 查找 URL 结束位置(空格、?、换行符等) url_end = url; while(*url_end && *url_end != ' ' && *url_end != '?' && *url_end != '\r' && *url_end != '\n'){ url_end++; } int len = url_end - url; if(len == 0){ // 根路径,使用默认文件 len = strlen("index.html"); req->parm = (char *)malloc(len + 1); if (req->parm == NULL) { return -1; } strcpy(req->parm, "index.html"); } else { len = MIN(len, 100); req->parm = (char *)malloc(len + 1); if (req->parm == NULL) { return -1; } memset(req->parm, 0, len + 1); memcpy(req->parm, url, len); } req->type = A_FILE; return 0; } void send_file(int sockfd, char *pathfile) { char *extension; const char *mimetype = NULL; char buffer[1024]; char filepath[1024]; if(NULL == pathfile || strlen(pathfile) == 0){ pathfile = "index.html"; } extension = strrchr(pathfile,'.'); if(NULL == extension) return; for(int i = 0; i < sizeof(mimetypes)/sizeof(mimetypes[0]); i++){ if(strcmp(extension,mimetypes[i].dot_extension) == 0){ mimetype = mimetypes[i].mimetype; break; } } if(NULL == mimetype){ return; } sprintf(filepath,"%s/%s",WEB_DIR,pathfile); printf("send_file() pathfile: %s\n",filepath); int fp = open(filepath,O_RDONLY); if(0 > fp){ perror("open() Fail to open file"); // 发送 404 错误响应 sprintf(buffer,"HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n%s\r\n404 Not Found\r\n",STD_HEADER); send(sockfd, buffer, strlen(buffer), 0); return; } // 构建并发送 HTTP 响应头 sprintf(buffer,"HTTP/1.1 200 OK\r\nContent-Type: %s\r\n%s\r\n",mimetype,STD_HEADER); int header_len = strlen(buffer); if(send(sockfd, buffer, header_len, 0) < 0){ perror("send_file() Fail to send header"); close(fp); return; } // 读取并发送文件内容 int n; while((n = read(fp, buffer, sizeof(buffer))) > 0){ if(send(sockfd, buffer, n, 0) < 0){ perror("send_file() Fail to send file content"); break; } } close(fp); } //main.c #include #include #include "server.h" int main(int argc, char *argv[]) { int sockfd = init_tcp(8080); if (sockfd < 0) { perror("init_tcp"); return -1; } pthread_t c_tid; struct sockaddr_in c_addr; socklen_t c_addr_len = sizeof(c_addr); printf("Server started 192.168.0.191:8080\n"); printf("Hello, World!\n"); while (1) { int new_sockfd = accept(sockfd, (struct sockaddr *)&c_addr, &c_addr_len); if (new_sockfd < 0) { perror("accept"); continue; } printf("New connection accepted\n"); // 将 int 值直接转换为指针传递,避免 malloc/free // 使用 intptr_t 确保类型转换安全 if (pthread_create(&c_tid, NULL, handle_thread, (void *)(intptr_t)new_sockfd) != 0) { perror("pthread_create"); close(new_sockfd); continue; } // 分离线程,让线程结束后自动清理资源 pthread_detach(c_tid); } close(sockfd); return 0; }

微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号