第十五章
(1)
标准I/O函数具有良好的移植性,不仅是I/O函数,所有标准函数具有良好的移植性,为了支持所有操作系统,这些函数都是按照ANSI C标准定义的
标准I/O函数可以利用缓冲提高性能,使用标准I/O函数时会得到额外的缓冲支持,需要传输的数据越多,有无缓冲带来的性能差异越大
(2)
使用标准I/O函数传输数据时,经过2个缓冲,通过fputs函数传输字符串时,首先将数据传递到标准I/O函数的缓冲,然后数据将移动到套接字输出缓冲,最后将字符串发送到对方主机
第十六章
(1)
abcd
(2)
无
第十七章
(1)
调用select函数后常见的针对所有文件描述符的循环语句
每次调用select函数时都需要向该函数传递监视对象信息
(2)
套接字是由操作系统管理的,监视套接字变化的函数必须要借助于操作系统才能完成功能
(3)
select函数每次调用时都向操作系统传递传递监视对象信息,而epoll仅向操作系统传递1次监视对象,监视范围或内容发生变化时只通知发生变化的事项,因为每种操作系统支持的程度和方式存在差异
(4)
服务器端接入者少,程序应具有兼容性
(5)
条件触发方式中,只要输入缓冲有数据就会一直通知该事件,边缘触发中仅在输入缓冲收到数据时注册1次该事件
(6)
因为边缘触发只注册一次事件,条件触发注册多次事件,如果强行分离数据的接收和处理时间点,服务器端不能承受,这种分离给服务器端带来了巨大的灵活性
(7)
chat_EPLTserv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#define BUF_SIZE 4
#define EPOLL_SIZE 50
#define MAX_CLNT 256
void error_handling(char *buf);
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
socklen_t adr_sz;
int str_len, i;
char buf[BUF_SIZE];
struct epoll_event *ep_events;
struct epoll_event event;
int epfd, event_cnt;
int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
if(argc != 2){
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
epfd = epoll_create(EPOLL_SIZE);
ep_events = malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
event.events = EPOLLIN;
event.data.fd = serv_sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);
while(1)
{
event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
if(event_cnt == -1)
{
puts("epoll_wait() error");
break;
}
puts("return epoll_wait");
for(i = 0; i < event_cnt; ++i)
{
if(ep_events[i].data.fd == serv_sock)
{
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
event.events = EPOLLIN;
event.data.fd = clnt_sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);
clnt_socks[clnt_cnt++] = clnt_sock;
printf("connected client: %d \n", clnt_sock);
}
else
{
str_len = read(ep_events[i].data.fd, buf, BUF_SIZE);
if(str_len == 0)
{
epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
for(int j = 0; j < clnt_cnt; ++j){
if(ep_events[i].data.fd == clnt_socks[j]){
while(j < clnt_cnt - 1)
{
clnt_socks[j] = clnt_socks[j + 1];
++j;
}
break;
}
}
--clnt_cnt;
close(ep_events[i].data.fd);
printf("closed client: %d \n", ep_events[i].data.fd);
}
else
{
for(int i = 0; i < clnt_cnt; ++i)
write(clnt_socks[i], buf, str_len);
}
}
}
}
close(serv_sock);
close(epfd);
return 0;
}
void error_handling(char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(1);
}
chat_EPETserv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <errno.h>
#define BUF_SIZE 4
#define EPOLL_SIZE 50
#define MAX_CLNT 256
void setnonblockingmode(int fd);
void error_handling(char *buf);
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
socklen_t adr_sz;
int str_len, i;
char buf[BUF_SIZE];
struct epoll_event *ep_events;
struct epoll_event event;
int epfd, event_cnt;
int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
if(argc != 2){
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
epfd = epoll_create(EPOLL_SIZE);
ep_events = malloc(sizeof(struct epoll_event) * EPOLL_SIZE);
setnonblockingmode(serv_sock);
event.events = EPOLLIN;
event.data.fd = serv_sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, serv_sock, &event);
while(1)
{
event_cnt = epoll_wait(epfd, ep_events, EPOLL_SIZE, -1);
if(event_cnt == -1)
{
puts("epoll_wait() error");
break;
}
puts("return epoll_wait");
for(i = 0; i < event_cnt; ++i)
{
if(ep_events[i].data.fd == serv_sock)
{
adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &adr_sz);
setnonblockingmode(clnt_sock);
event.events = EPOLLIN | EPOLLET;
event.data.fd = clnt_sock;
epoll_ctl(epfd, EPOLL_CTL_ADD, clnt_sock, &event);
clnt_socks[clnt_cnt++] = clnt_sock;
printf("connected client: %d \n", clnt_sock);
}
else
{
while(1)
{
str_len = read(ep_events[i].data.fd, buf, BUF_SIZE);
if(str_len == 0)
{
epoll_ctl(epfd, EPOLL_CTL_DEL, ep_events[i].data.fd, NULL);
for(int j = 0; j < clnt_cnt; ++j){
if(ep_events[i].data.fd == clnt_socks[j]){
while(j < clnt_cnt - 1)
{
clnt_socks[j] = clnt_socks[j + 1];
++j;
}
break;
}
}
--clnt_cnt;
close(ep_events[i].data.fd);
printf("closed client: %d \n", ep_events[i].data.fd);
break;
}
else if(str_len < 0)
{
if(errno == EAGAIN)
break;
}
else
{
for(int i = 0; i < clnt_cnt; ++i)
write(clnt_socks[i], buf, str_len);
}
}
}
}
}
close(serv_sock);
close(epfd);
return 0;
}
void setnonblockingmode(int fd)
{
int flag = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}
void error_handling(char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(1);
}
第十八章
(1)
系统将CPU时间分成多个微小的块后分配给多个进程
运行程序前需要将相应进程信息读入内存,如果运行进程A后需要紧接着运行进程B,就应该将进程A相关信息移出内存,并读入进程B相关信息,这就是上下文切换
(2)
同一进程的线程间共享数据区和堆,上下文切换时不需要切换数据区和堆,可以利用数据区和堆交换数据
(3)
进程在操作系统构成单独执行流的单位
线程在进程构成单独执行流的单位
(4)
bcd
(5)
d
(6)
调用pthread_join函数或调用pthread_detach函数
(7)
echo_multithreadserv.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>
#define BUF_SIZE 100
#define MAX_CLNT 256
void *handle_clnt(void *arg);
void error_handling(char *buf);
int clnt_cnt = 0;
int clnt_socks[MAX_CLNT];
char buf[BUF_SIZE];
pthread_mutex_t mutx;
pthread_mutex_t mutx_2;
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
struct sockaddr_in serv_adr, clnt_adr;
int clnt_adr_sz;
pthread_t t_id;
if(argc != 2){
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
pthread_mutex_init(&mutx, NULL);
pthread_mutex_init(&mutx_2, NULL);
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
while(1){
clnt_adr_sz = sizeof(clnt_adr);
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
pthread_mutex_lock(&mutx);
clnt_socks[clnt_cnt++] = clnt_sock;
pthread_mutex_unlock(&mutx);
pthread_create(&t_id, NULL, handle_clnt, (void*)&clnt_sock);
pthread_detach(t_id);
printf("Connected client IP: %s \n", inet_ntoa(clnt_adr.sin_addr));
}
close(serv_sock);
return 0;
}
void *handle_clnt(void *arg){
int clnt_sock = *((int*)arg);
int str_len = 0, i;
char msg[BUF_SIZE];
while(1)
{
pthread_mutex_lock(&mutx_2);
str_len=read(clnt_sock, msg, sizeof(msg));
pthread_mutex_unlock(&mutx_2);
if(str_len == 0)
break;
pthread_mutex_lock(&mutx_2);
write(clnt_sock, msg, str_len);
pthread_mutex_unlock(&mutx_2);
sleep(1);
}
pthread_mutex_lock(&mutx);
for(i = 0; i < clnt_cnt; ++i){
if(clnt_sock == clnt_socks[i]){
while(i < clnt_cnt - 1)
{
clnt_socks[i] = clnt_socks[i + 1];
++i;
}
break;
}
}
--clnt_cnt;
pthread_mutex_unlock(&mutx);
close(clnt_sock);
return NULL;
}
void error_handling(char *buf)
{
fputs(buf, stderr);
fputc('\n', stderr);
exit(1);
}
(8)
不同步多线程访问临界区会产生问题,同步的话由于read阻塞,同一时间只有一个客户端线程的消息能够读取