《UNIX网络编程 卷1》 笔记: 多线程—web客户程序
来源:互联网 发布:单片机晶振电容选择 编辑:程序博客网 时间:2024/06/05 15:33
在非阻塞式connect—web客户程序一节中,我们使用非阻塞式connect(对于每个待读取的文件,向服务器发起非阻塞连接)和select(监听所有的套接字描述符)实现了一个web客户程序,本节我们使用线程来实现同样的功能。
我们为每个待读取的文件创建一个线程,这个线程完成从服务器上读取文件的工作。因而我们修改了之前定义的file结构体:
struct file {char *f_name; /*文件名*/char *f_host; /*服务器主机名*/int f_flags; /*状态*/pthread_t f_tid; /*线程ID*/} file[MAXFILES];我们添加了表示线程ID的f_tid成员,移除了套接字描述符成员f_fd(我们不需要监听套接字描述符)。
读取文件的状态也只需要两种:
#define F_DONE 1 /*读取文件完成*/#define F_JOINED 2 /*读取文件的线程已经终止*/我们增加了三个全局变量,一个表示“条件”的变量、互斥锁和条件变量。主线程使用该条件变量等待有子线程退出,然后调用pthread_join获取其终止状态:
int ndone; /*不为0表示有线程退出*/pthread_mutex_t ndone_mutex = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t ndone_cond = PTHREAD_COND_INITIALIZER;
线程函数代码如下,它完成从服务器上读取文件的任务。
void *do_get_read(void *vptr){int fd, n;char line[MAXLINE];struct file *fptr;fptr = (struct file *)vptr;fd = Tcp_connect(fptr->f_host, SERV); /*连接到服务器*/printf("do_get_read for %s, fd %d, thread %d\n", fptr->f_name, fd, fptr->f_tid);write_get_cmd(fptr); /*发起读取文件GET命令*/for ( ; ; ) { /*读取文件*/if ((n = Read(fd, line, MAXLINE)) == 0)break;printf("read %d bytes from %s\n", n, fptr->f_name);}printf("end-of-file on %s\n", fptr->f_name);Close(fd);Pthread_mutex_lock(&ndone_mutex);fptr->f_flags = F_DONE;ndone++;Pthread_cond_signal(&ndone_cond);Pthread_mutex_unlock(&ndone_mutex);/*返回fptr*/return fptr;}主函数的代码如下:
int nconn, nfiles, nlefttoconn, nlefttoread;int main(int argc, char **argv){int i, n, maxnconn;pthread_t tid;struct file *fptr;if (argc < 5)err_quit("usage: web <#conns> <hostname> <homepage> <file1> ...");maxnconn = atoi(argv[1]); /*最大连接数*/nfiles = min(argc - 4, MAXFILES);for (i = 0; i < nfiles; i++) {file[i].f_name = argv[i + 4]; /*文件名*/file[i].f_host = argv[2]; /*服务器主机名*/file[i].f_flags = 0;}printf("nfiles = %d\n", nfiles);/*访问服务器主页*/home_page(argv[2], argv[3]);nlefttoread = nlefttoconn = nfiles;nconn = 0;while (nlefttoread > 0) {while (nconn < maxnconn && nlefttoconn > 0) {/*找到一个文件去读*/for (i = 0; i < nfiles; i++)if (file[i].f_flags == 0)break;if (i == nfiles)err_quit("nlefttoconn = %d but nothing found", nlefttoconn);/*为获取每个文件创建一个线程*/Pthread_create(&tid, NULL, &do_get_read, &file[i]);file[i].f_tid = tid;nconn++;nlefttoconn--;}Pthread_mutex_lock(&ndone_mutex);while (ndone == 0)Pthread_cond_wait(&ndone_cond, &ndone_mutex); /*等待一个线程完成任务并退出*/for (i = 0; i < nfiles; i++) {if (file[i].f_flags & F_DONE) {/*等待完成任务的线程终止,获取它的退出状态*/Pthread_join(file[i].f_tid, (void **)&fptr);if (&file[i] != fptr)err_quit("file[i] != fptr");fptr->f_flags = F_JOINED;ndone--;nconn--;nlefttoread--;printf("thread %d for %s done\n", fptr->f_tid, fptr->f_name);}}Pthread_mutex_unlock(&ndone_mutex);}exit(0);}home_page函数和write_get_cmd函数仍使用之前的版本。
主函数不再使用select监听任何描述符,因为读取文件的任务已经由子线程完成了,它(主线程)只需等待有子线程退出(程序参数conns限制了同时建立的最大连接数,也就限制了能同时创建的线程的数量),然后等待其终止,再创建新的线程继续读取文件。
阅读全文
0 0
- 《UNIX网络编程 卷1》 笔记: 多线程—web客户程序
- 《UNIX网络编程 卷1》 笔记: 非阻塞式connect—web客户程序
- 《UNIX网络编程 卷1》 笔记: TCP 客户/服务器程序示例
- UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式
- Unix网络编程(卷1)—笔记
- 学习 UNIX网络编程卷1:套接字 笔记1-实现一个简单的回射客户服务器程序
- UNIX网络编程卷一 笔记 第五章 TCP客户/服务器程序示例
- UNIX网络编程卷1 回射客户程序 UDP 超时设置
- UNIX网络编程卷1:套接字联网-第5章:TCP客户/服务器程序示例
- 《UNIX网络编程 卷1》 笔记: 原始套接字—ping程序
- 《UNIX网络编程 卷1》 笔记: 广播
- 《UNIX网络编程 卷1》 笔记: 线程
- 《UNIX网络编程 卷1》 笔记: UNIX域协议
- Unix网络编程 第一卷 套接口API 第五章 TCP客户/服务器程序例子
- UNIX网络编程卷一:第五章 TCP客户/服务器程序实例
- UNIX网络编程卷一 第五章 TCP客户/服务器程序示例
- UNIX网络编程——非阻塞connect: Web客户程序
- UNIX网络编程笔记(4)—TCP客户/服务器程序示例
- Python Coding 小技巧
- Cmake Practice
- 背包总结
- hdu4568
- vsftpd安装文档
- 《UNIX网络编程 卷1》 笔记: 多线程—web客户程序
- [JZOJ5129][SDOI省队集训2017]字符串
- 55 C语言条件运算符
- 如何查看JSP和Servlet版本
- Atom 安装
- Java Web 概论
- HDU 4572 Bottles Arrangement(数学推公式)——2013 ACM-ICPC长沙赛区全国邀请赛
- SpringBoot安装起步,第一个Demo
- 多线程-线程控制之礼让线程